เพื่อให้ระบบ 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 ไม่ผ่าน
