เพื่อให้ระบบ Spring Security สามารถดึงข้อมูลจากตาราง users, roles, และ permissions ที่เราออกแบบไว้ (สไตล์ Laravel) มาใช้ในการ Login ได้จริง คุณต้องสร้างไฟล์ 2 ส่วนหลัก คือ UserDetails (เพื่อบอก Spring ว่าจะเช็คฟิลด์ไหน) และ SecurityConfig (เพื่อตั้งค่าการเข้าถึง) ครับ
สร้าง CustomUserDetails Service
ไฟล์นี้ทำหน้าที่เหมือน “สะพาน” เชื่อมระหว่างฐานข้อมูล SQL Server กับ Spring Security ครับ
src/main/java/com/example/demo/config/UserDetailsServiceImpl.java
package com.example.demo.config;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;
import java.util.stream.Collectors;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername (String username) throws UsernameNotFoundException {
// หา User จาก DB (ถ้าไม่เจอให้โยน Error เหมือน Laravel Auth) User user = userRepository.findByUsername (username) .orElseThrow ( () -> new UsernameNotFoundException ("User not found: " + username)) ;
// แปลง Roles/Permissions ให้เป็น SimpleGrantedAuthority ของ Spring
return new org.springframework.security.core.userdetails.User (user.getUsername () ,
user.getPassword () ,
user.getRoles () .stream () .map (role -> new SimpleGrantedAuthority (role.getName ())) .collect (Collectors.toList ())) ;
}
}
สร้าง SecurityConfig (Spring Boot 3.x Style)
ไฟล์นี้คือ “ประตูด่านหน้า” ที่คุมสิทธิ์การเข้าถึง API ทั้งหมดครับ
src/main/java/com/example/demo/config/SecurityConfig.java
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
http
.csrf (csrf -> csrf.disable ()) // ปิดไว้สำหรับการทำ Stateless API (เหมือน Laravel API) .authorizeHttpRequests (auth -> auth
.requestMatchers ("/api/auth/**") .permitAll () // เปิดให้ Register/Login ได้
.requestMatchers ("/api/admin/**") .hasRole ("ADMIN") // เฉพาะ Role ADMIN เท่านั้น
.anyRequest () .authenticated () // ที่เหลือต้อง Login ทั้งหมด) .httpBasic (Customizer.withDefaults ()) ; // ใช้ Basic Auth ในการทดสอบเบื้องต้น
return http.build () ;
}
// ตัวเข้ารหัส Password (ต้องใช้ตัวนี้ตอนสมัครสมาชิกด้วย เพื่อให้ Match กัน) @Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder () ;
}
@Bean
public AuthenticationManager authenticationManager (AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager () ;
}
}
สิ่งที่ต้องระวัง (Common Pitfalls)
- Prefix ของ Role: ใน Spring Security ถ้าคุณใช้
.hasRole ("ADMIN")มันจะมองหาคำว่าROLE_ADMINในฐานข้อมูลโดยอัตโนมัติ ดังนั้นในตารางrolesของคุณ ควรตั้งชื่อเป็นROLE_ADMINครับ - Password Encoding: เวลาคุณเพิ่ม User ลงในฐานข้อมูล (Seed Data) ห้าม ใส่ Password เป็นข้อความธรรมดา (Plain Text) ต้องใช้
BCryptเท่านั้น มิฉะนั้นจะ Login ไม่ผ่าน