Contents

วิธีรักษาความปลอดภัยแอปพลิเคชัน Spring ของคุณด้วย Spring Security

Spring Security เป็นวิธีที่มีประสิทธิภาพในการปกป้องแอปพลิเคชันผ่านกระบวนการรับรองความถูกต้องและการอนุญาต ตามค่าเริ่มต้น เฟรมเวิร์กนี้กำหนดให้ URL หรือเว็บเพจแต่ละรายการภายในแอปพลิเคชันต้องเข้าถึงได้ด้วยข้อมูลรับรองของผู้ใช้ปลายทางคนเดียวที่เป็นที่รู้จักทั่วโลก

วิธีการที่นำเสนอแสดงให้เห็นถึงความสามารถในการปรับตัวที่ยอดเยี่ยม ช่วยให้สามารถกำหนดระเบียบการรักษาความปลอดภัยที่ปรับแต่งสำหรับทุกเส้นทางคำขอ HTTP แต่ละรายการภายในโปรแกรมของคุณ พร้อมด้วยผู้ใช้ปลายทางที่แตกต่างกัน ด้วยเหตุนี้ จึงมีความเป็นไปได้ที่จะขจัดข้อจำกัดด้านความปลอดภัยที่บังคับใช้กับหน้าเว็บที่ไม่ต้องการการรับรองความถูกต้องของผู้ใช้ เช่น หน้าแรก ยิ่งไปกว่านั้น วิธีการนี้อนุญาตให้กำหนดการกำหนดบทบาทและระดับอำนาจสำหรับผู้ใช้เฉพาะประเภท

การเพิ่ม Spring Security ให้กับแอปพลิเคชันของคุณ

เมื่อรวม Spring Security เข้ากับแอ็พพลิเคชัน Spring Boot ที่มีอยู่หรือที่สร้างขึ้นใหม่ จะมีวิธีหลักสองวิธีในการนำไปใช้งาน ข้อแรกเกี่ยวข้องกับการเลือกการผสานรวมระหว่างกระบวนการสร้างโปรเจ็กต์ Spring Boot ใหม่โดยใช้แพลตฟอร์ม Spring Initializr หรืออีกทางหนึ่งอาจเลือกที่จะรวมไว้ในข้อกำหนดการสร้างของโครงการโดยเพิ่มลงในรายการอ้างอิงในเอกสารดังกล่าวภายหลังการสร้างโครงการ

ไฟล์การกำหนดค่าสำหรับ Gradleprojects จะถูกระบุเป็น build.gradle เมื่อเลือกผ่านตัวเลือกแรก ในขณะที่โปรเจ็กต์ inMaven เหล่านั้นจะถูก denotedaspom.xml

ไฟล์ build.gradle ของคุณควรมีการพึ่งพาเฉพาะ ดังที่อธิบายไว้ด้านล่าง:

 dependencies {
      implementation 'org.springframework.boot:spring-boot-starter-security'
} 

ไฟล์ XML ของพอร์ตโฟลิโอที่กล่าวถึงข้างต้นคาดว่าจะรวมการพึ่งพาที่เฉพาะเจาะจง ซึ่งมีรายละเอียดดังต่อไปนี้:

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
</dependency> 

แอปพลิเคชันตัวอย่างที่ให้มาสามารถเข้าถึงได้ผ่านที่เก็บ GitHub ซึ่งให้บริการฟรีภายใต้เงื่อนไขของใบอนุญาต MIT ทำให้ผู้ใช้สามารถใช้แอปพลิเคชันได้ตามเงื่อนไขที่ระบุ

การใช้ Spring Security

เมื่อรวมโมดูล Spring Security เข้ากับโปรเจ็กต์ของคุณแล้ว ตอนนี้คุณก็พร้อมที่จะปรับใช้ฟังก์ชันต่างๆ โดยไม่ชักช้า ในการสาธิตสิ่งนี้ เพียงเปิดโปรแกรมของคุณและนำทางเบราว์เซอร์ของคุณไปยังเว็บไซต์อย่างเป็นทางการของ Spring Boot หรือหน้าที่กำหนดภายในแอปพลิเคชันของคุณเอง ตัวอย่างที่ให้มานี้ใช้ตัวควบคุมหลักที่ควบคุมเหนือการจัดการมาตรฐานของคำขอขาเข้าที่มุ่งไปยัง URL ที่กำหนดค่าไว้ล่วงหน้า http://localhost:8080

 package com.springSecurityDemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WebController {
   
     @GetMapping("/")
      public String home() {
           return "Welcome!";
      }
} 

แอ็พพลิเคชันดังกล่าวเมื่อรวมคลาสตัวควบคุมเดี่ยวดังกล่าวแล้ว ให้มุมมองเริ่มต้นดังนี้:

/th/images/spring-security-app-default-login-page.jpg

เมื่อเข้าถึงแอปพลิเคชันเป็นครั้งแรก จะถูกนำไปที่หน้า localhost:8080/login ก่อนที่จะเข้าถึงส่วนอื่น ๆ ของโปรแกรม ผู้ใช้ต้องป้อนชื่อผู้ใช้ที่กำหนดไว้ล่วงหน้า ซึ่งก็คือ “ผู้ใช้” พร้อมกับรหัสผ่านที่สร้างขึ้นแบบสุ่ม ซึ่งสามารถพบได้ในพร้อมท์คำสั่ง พร้อมรับคำสั่งสร้างข้อความที่คล้ายกับตัวอย่างต่อไปนี้:

 Using generated security password: c4070465-4c65-4e72-8c3f-3800e631ba81 

เมื่อรีสตาร์ทแอปพลิเคชันในภายหลัง รหัสผ่านที่สร้างขึ้นโดยอัตโนมัติจะได้รับการเปลี่ยนแปลง อย่างไรก็ตาม ชื่อผู้ใช้จะยังคงอยู่ไม่เปลี่ยนแปลง เมื่อป้อนชื่อผู้ใช้และรหัสผ่านที่กำหนดไว้ล่วงหน้า ระบบจะเปลี่ยนเส้นทางไปยังอินเทอร์เฟซที่เกี่ยวข้องภายในแอปพลิเคชัน

ปรับแต่ง Spring Security

เพื่อปรับแต่งความปลอดภัยของแอปพลิเคชันของคุณตามความต้องการเฉพาะของคุณ จำเป็นต้องแก้ไขการกำหนดค่าเริ่มต้นที่ Spring Security จัดเตรียมไว้ให้ อย่างไรก็ตาม ก่อนที่จะดำเนินการดังกล่าว สมมติว่าคุณได้ตั้งค่าเว็บแอปพลิเคชันพื้นฐานโดยใช้ Spring แล้ว มีข้อกำหนดเบื้องต้นเพิ่มเติมหลายประการที่ต้องปฏิบัติตามเพื่อใช้ตัวอย่างเฉพาะนี้:

⭐สปริงข้อมูล JPA

⭐ไดรเวอร์ MySQL JDBC

⭐ไทมีลีฟ

⭐ลอมบอก

การใช้กรอบงาน Thymeleaf ทำให้สามารถสร้างมุมมองที่หลากหลายได้ ในขณะที่ Lombok ปรับปรุงกระบวนการเขียนโค้ดภายในโครงสร้างคลาสแบบอ็อบเจกต์ นอกจากนี้ การรวมเข้ากับไลบรารี JPA และไดรเวอร์ MySQL ยังช่วยอำนวยความสะดวกในการโต้ตอบกับฐานข้อมูล MySQL แม้ว่าผู้ใช้อาจใช้ฐานข้อมูลทางเลือกก็ตาม ในการกำหนดค่าการโต้ตอบดังกล่าว จำเป็นต้องปรับการตั้งค่าคอนฟิกูเรชันที่มีอยู่ในไฟล์ applications.properties ซึ่งอยู่ภายในไดเร็กทอรีรีซอร์ส

 spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/spring_security
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update 

เพื่อสร้างการเชื่อมต่อกับอินสแตนซ์ในเครื่องของ MySQL ซึ่งระบุว่าเป็น"spring\_security"โดยใช้ชื่อผู้ใช้"รูท"และรหัสผ่าน"(1234)“จำเป็นต้องกำหนดค่ารหัสการกำหนดค่าที่ให้มาอย่างถูกต้องโดยการอัปเดต ข้อมูลที่เกี่ยวข้องเพื่อให้เข้ากันได้กับการกำหนดค่าฐานข้อมูลเฉพาะ

เมื่อคุณเพิ่มการพึ่งพาที่จำเป็นและสร้างฐานข้อมูลของคุณแล้ว คุณอาจเริ่มกำหนดจำนวนของเปอร์สเปคทีฟที่แอปพลิเคชันของคุณจะครอบคลุม นอกจากนี้ สิ่งสำคัญคือต้องพิจารณามาตรการรักษาความปลอดภัยสำหรับแต่ละจุดชมวิว ในตัวอย่างของเรา มีจุดได้เปรียบที่แตกต่างกันหกจุดที่รวมอยู่ในแอปพลิเคชัน

⭐หน้าแรก

⭐หน้าลงทะเบียน

⭐หน้าเข้าสู่ระบบ

⭐หน้าออกจากระบบ

⭐หน้าผู้ใช้

⭐หน้าข้อผิดพลาด

เพื่อให้ผู้ใช้สามารถเข้าถึงข้อมูลส่วนบุคคลของตนใน “หน้าผู้ใช้” ได้ ผู้ใช้จะต้องลงทะเบียนและเข้าสู่ระบบแอปพลิเคชันก่อน เฉพาะผู้ที่ลงทะเบียนเท่านั้นที่ได้รับอนุญาตให้ดูหน้านี้ นอกจากนี้ จำเป็นต้องสร้างแพ็คเกจเพิ่มเติมอีกสี่แพ็คเกจภายในแอปพลิเคชันนอกเหนือจากที่มีให้ในข้อเสนอมาตรฐานของ Spring Boot

คลาสควบคุมการลงทะเบียน

แพ็คเกจคอนโทรลเลอร์ประกอบด้วยคลาสที่รับผิดชอบในการประมวลผลคำขอ HTTP โดยทั่วไป คลาสตัวควบคุมเดี่ยวจะจัดการคำขอที่สอดคล้องกับฟังก์ชันการทำงานของเว็บเพจเฉพาะ เช่น ในอินสแตนซ์ของคลาส WebController ในทางกลับกัน RegisterView ต้องการการจัดการฟังก์ชันการทำงานที่แตกต่างกัน ดังนั้นจึงจำเป็นต้องมีคลาสคอนโทรลเลอร์ส่วนตัวโดยเฉพาะ

 @Controller
@RequestMapping("/register")
public class RegistrationController {
       private UserRepository userRepo;
       private PasswordEncoder passwordEncoder;
       
       public RegistrationController( UserRepository userRepo, PasswordEncoder passwordEncoder) {
             this.userRepo = userRepo;
             this.passwordEncoder = passwordEncoder;
       }
       @GetMapping
       public String registerForm() {
             return "registration";
       }
       @PostMapping
       public String processRegistration(RegistrationForm form) {
             userRepo.save(form.toUser(passwordEncoder));
             return "redirect:/login";
       }
} 

RegisterController'ทำหน้าที่เป็นจุดเริ่มต้นสำหรับฟังก์ชันความปลอดภัยภายในแอปพลิเคชันของเรา โดยมีการจัดการคำขอที่ส่งตรงไปยัง localhost:8080/register สิ่งนี้ระบุโดยคำอธิบายประกอบ @RequestMapping ` ซึ่งระบุประเภทคำขอเฉพาะที่ตัวควบคุมนี้ออกแบบมาเพื่อจัดการ

คำอธิบายประกอบ @GetMapping'บ่งบอกว่าเมื่อแอปพลิเคชันพบคำขอสำหรับ/register เมธอด registerForm()‘จะรับผิดชอบในการประมวลผลคำขอนี้และแสดงมุมมองการลงทะเบียนที่เกี่ยวข้อง

หลังจากที่ผู้เยี่ยมชมคลิกปุ่มลงทะเบียน คำอธิบายประกอบ @PostMapping จะเข้ามามีบทบาท เมธอด processRegistration() อนุญาตให้คุณโพสต์ข้อมูลผู้ใช้ที่ได้รับจากคลาส RegisterForm ไปยังฐานข้อมูล โดยใช้คลาส UserRepository แต่ก่อนที่จะเก็บข้อมูลนี้ เมธอด processRegistration() จะเข้ารหัสรหัสผ่านของผู้ใช้โดยใช้ Spring’s ส่วนติดต่อ PasswordEncoder

การสร้างการกำหนดค่าความปลอดภัยใหม่

การใช้ Spring 3.1 เบื้องต้นทำให้นักพัฒนาสามารถใช้แนวทาง Java เพื่อกำหนดค่า Spring Security ผ่านการใช้คลาสแทนที่จะใช้การกำหนดค่าแบบ XML สิ่งสำคัญสำหรับกระบวนการนี้คือการรวมเอา

 @Configuration
public class SecurityConfiguration {
} 

คำอธิบายประกอบ @Configuration บ่งบอกว่าคลาสที่ตามมาประกอบด้วยคลาสการกำหนดค่า ซึ่งเป็นเครื่องมือสำคัญในการจัดเตรียมส่วนประกอบให้กับบริบทของแอปพลิเคชัน Spring คอนเทนเนอร์นี้ทำหน้าที่เป็นเครื่องมือสำหรับ Spring ในการสร้างและจัดการองค์ประกอบต่างๆ (หรือส่วนประกอบ) ของแอปพลิเคชัน ในคลาส SecurityConfiguration ส่วนประกอบเริ่มต้นที่ระบุจะแสดงด้วยการกำหนด ` passwordEncoder’

 @Bean
public PasswordEncoder passwordEncoder() {
 return new BCryptPasswordEncoder();
} 

RegisterController'ใช้ถั่ว'passwordEncoder'สำหรับการเข้ารหัสรหัสผ่านที่สร้างขึ้นใหม่ก่อนที่จะจัดเก็บในฐานข้อมูล นอกจากนี้ SecurityConfiguration’ยังต้องการการรวม bean userDetailsService เพื่อให้ทำงานได้อย่างเหมาะสม

 @Bean
public UserDetailsService userDetailsService(UserRepository userRepo) {
 return username -> {
   Customer customer = userRepo.findByUsername(username);
     if (customer != null)
           return customer;
     throw new UsernameNotFoundException("Customer '" \+ username \+ "' not found");
 };
} 

userDetailsService bean ใช้ Spring Security’s ส่วนต่อประสาน UserDetailsService เพื่อดึงชื่อผู้ใช้และรหัสผ่านของผู้ใช้สำหรับการตรวจสอบสิทธิ์ ในระหว่างเซสชันการเข้าสู่ระบบของลูกค้า ดังนั้น ทันทีที่ลูกค้าคลิกปุ่มเข้าสู่ระบบในมุมมองการเข้าสู่ระบบ userDetailsService bean จะเริ่มเคลื่อนไหว

ด้วยการใช้อินเทอร์เฟซ UserRepository'bean'userDetailsService'จะได้รับสิทธิ์ในการเข้าถึงคอลเลกชันที่ครอบคลุมของผู้ใช้ที่จัดเก็บไว้ในฐานข้อมูล อินเทอร์เฟซต่อมาใช้ UserRepository’เพื่อระบุผู้ใช้ที่มีข้อมูลรับรองตรงกับชื่อผู้ใช้และรหัสผ่านที่ให้ไว้ หลังจากนั้นจะดึงและส่งคืนข้อมูลที่เกี่ยวข้องทั้งหมดที่เกี่ยวข้องกับลูกค้ารายนั้นๆ เป็นเอนทิตีแบบรวม

เมื่อตรวจสอบความถูกต้องของข้อมูลประจำตัวที่ให้มาสำเร็จ หากเอนทิตีที่ดึงมานั้นสอดคล้องกับลูกค้าที่ลงทะเบียน พวกเขาได้รับอนุญาตให้ใช้ฟีเจอร์ของแพลตฟอร์ม ในกรณีที่การตรวจสอบล้มเหลวและมีการป้อนชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง อินเทอร์เฟซจะได้รับการโหลดซ้ำอย่างราบรื่น โดยเชิญผู้ใช้ปลายทางให้ป้อนข้อมูลการเข้าสู่ระบบที่ถูกต้องสำหรับความพยายามอีกครั้ง

ห่วงโซ่ตัวกรอง

Spring Security’s อินเทอร์เฟซ SecurityFilterChain เป็นอินเทอร์เฟซการเขียนโปรแกรมแอปพลิเคชัน (API) ที่มีประโยชน์ ที่มีบทบาทสำคัญในการกำหนดค่า Spring Security อินเทอร์เฟซนี้ทำงานร่วมกับ Spring Security’s HttpSecurity คลาสเพื่อสร้างห่วงโซ่ตัวกรองสำหรับคำขอ HTTP เฉพาะ

 @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  http
  .authorizeHttpRequests((authorize) -> authorize
              .requestMatchers("/user").hasAuthority("USER").anyRequest().permitAll())
  .formLogin(formLogin-> formLogin
              .loginPage("/login").defaultSuccessUrl("/user", true))
  .logout(logout-> logout.logoutSuccessUrl("/logout"));
  return http.build();
} 

โค้ดที่ให้มานี้ใช้คลาส HttpSecurity ภายใน filterChain เพื่อบังคับใช้มาตรการรักษาความปลอดภัยโดยการจำกัดการเข้าถึงไปยังปลายทางเฉพาะตามบทบาทของผู้ใช้ โดยเฉพาะอย่างยิ่ง การกำหนดค่า HttpSecurity'อนุญาตให้เข้าถึงจุดสิ้นสุด/user’เฉพาะกับผู้ใช้ที่มีบทบาท"USER"เท่านั้น ซึ่งกำหนดโดยการใช้เมธอด `getAuthorities()‘ที่พบในอ็อบเจกต์ลูกค้าที่สร้างขึ้นใหม่ทุกรายการ

 @Override
public Collection<? extends GrantedAuthority> getAuthorities() {
 return Arrays.asList(new SimpleGrantedAuthority("USER"));
}

ห่วงโซ่ตัวกรองช่วยให้เข้าถึงทุก URL ภายในแอปพลิเคชันได้อย่างไม่จำกัดสำหรับผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์ เนื่องจากใช้ประโยชน์จากขั้นตอนการเข้าสู่ระบบและออกจากระบบของฟอร์มที่มีให้โดยคลาส HttpSecurity

การใช้เทคนิคเหล่านี้ช่วยให้การนำทางราบรื่นสำหรับผู้ใช้ที่ดำเนินการสำเร็จแล้ว ตัวอย่างเช่น เมื่อป้อนข้อมูลประจำตัวที่ถูกต้องและคลิกปุ่ม"เข้าสู่ระบบ"บนหน้า”/เข้าสู่ระบบ"ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยังหน้า"/ผู้ใช้"อย่างง่ายดายโดยไม่ต้องดำเนินการใดๆ จากส่วนท้าย

โดยสรุป filterChain bean สร้างและให้ผลลัพธ์เป็น filter chain ซึ่งช่วยให้ผู้ใช้ปลายทางที่ได้รับการรับรองความถูกต้องสามารถเข้าสู่แพลตฟอร์มซอฟต์แวร์ได้ ฟังก์ชันร่วมกันของส่วนประกอบทั้งสามภายในคลาสการกำหนดค่า SecurityConfiguration คือการปกป้องแอปพลิเคชันของคุณจากการเข้าถึงโดยไม่ได้รับอนุญาต

filterChain bean มีบทบาทสำคัญในการกำหนดระดับการให้สิทธิ์สำหรับทุกคำขอ HTTP ที่เข้ามา อิทธิพลของมันเพิ่มขึ้นเมื่อมีการเพิ่มหน้าเว็บเพิ่มเติมในแอปพลิเคชัน ทำให้ filterChain bean สามารถสร้างระดับความปลอดภัยได้

ประโยชน์หลักของ Spring Security

Spring Security มอบความสามารถที่หลากหลายสำหรับการควบคุมทั้งบุคคลที่ได้รับอนุญาตและขอบเขตของสิทธิ์ที่จ่ายให้กับผู้ที่อยู่ภายในโดเมนของแอปพลิเคชันของคุณ (โดยใช้รายชื่อบทบาทผู้ใช้ที่แข็งแกร่ง) การใช้กลไกการควบคุมการเข้าถึงอย่างมีประสิทธิภาพถือเป็นข้อพิจารณาที่สำคัญยิ่งในการพัฒนาโซลูชันซอฟต์แวร์ การให้ผู้ใช้จำนวนมากเข้ามาอย่างอิสระเนื่องจากมาตรการจำกัดการเข้าถึงไม่เพียงพออาจส่งผลให้เกิดค่าใช้จ่ายจำนวนมากและการละเมิดความปลอดภัยที่อาจเกิดขึ้นโดยไม่ได้ตั้งใจ