# SPRING BOOT 3 SECURITY
securityfilterchain spring boot 3 @bean error
我在更新spring boot 2.7 更新到 spring boot 3.3.11
出現securityfilterchain spring boot 3 @bean error
錯誤
ChatGPT 說:
你在將 Spring Boot 從 2.7 升級到 3.3.11 時遇到 SecurityFilterChain 的 @Bean 錯誤,這是很常見的問題,因為 Spring Security 在 Spring Boot 3.x 中進行了重大變更。
✅ Spring Boot 3 / Spring Security 6 改動重點:
Spring Security 6(隨 Spring Boot 3 使用)不再使用 WebSecurityConfigurerAdapter,取而代之的是配置 SecurityFilterChain 的 Bean。
✅ 正確範例(Spring Boot 3 / Spring Security 6):
你應該這樣寫你的 SecurityFilterChain:
java
複製
編輯
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
}
🧨 常見錯誤:
1. 沒有回傳 http.build()
java
複製
編輯
// 錯誤!沒有 return http.build()
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(...);
}
2. 使用舊的 .antMatchers()(已棄用)
java
複製
編輯
// 錯誤!Spring Security 6 棄用 antMatchers
http.authorizeHttpRequests().antMatchers("/**").permitAll();
✅ 請改用:
java
複製
編輯
http.authorizeHttpRequests().requestMatchers("/**").permitAll();
🛠 其他注意事項
如果你還在用 WebSecurityConfigurerAdapter 👇
java
複製
編輯
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ⚠️ Spring Security 6 不支援這種方式了
}
這樣會導致錯誤,請完全移除 extends WebSecurityConfigurerAdapter,改用 SecurityFilterChain bean。
📦 依賴版本建議
請確認你的 pom.xml 或 build.gradle 有正確的 Spring Security 6 依賴,例如:
groovy
複製
編輯
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
}
如果你可以貼上錯誤訊息(stack trace)或目前的配置程式碼,我可以幫你更具體排錯 🔍
你說:
是有關於@bean的問題
ChatGPT 說:
了解,你提到的錯誤是關於 @Bean 標註 SecurityFilterChain 時發生問題。這通常與以下幾個常見問題有關:
🔍 請先檢查這個方法定義:
java
複製
編輯
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/**").permitAll()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
✅ @Bean 方法常見錯誤排查
錯誤情況 解釋與解法
未回傳 SecurityFilterChain @Bean 方法必須明確 return http.build();
方法簽名錯誤 public SecurityFilterChain securityFilterChain(HttpSecurity http) 是必要的簽名,錯誤的參數或回傳型別都會報錯
缺少 @Configuration 或 @EnableWebSecurity Spring 不會掃描 @Bean 方法,如果這些註解沒加上
方法名稱不一致但被引用了舊名稱 確保方法名不會在其他地方錯誤地引用
其他配置類別衝突或重複定義 確保沒有多個 SecurityFilterChain Bean,否則會有重複定義錯誤
🧨 常見錯誤訊息
如果你有看到像這樣的錯誤訊息:
❌ Parameter 0 of method securityFilterChain... could not be resolved
說明 Spring 容器無法注入 HttpSecurity。這通常是:
少了 @EnableWebSecurity
你用了不正確的參數(應該是 HttpSecurity)
✅ 正確配置範例(完整版)
java
複製
編輯
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
// 可選:提供 AuthenticationManager
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
}
如果你可以提供 具體錯誤訊息 或你現在的 SecurityConfig 程式碼,我可以幫你精準對應問題點。要不要貼上來我幫你看?
你說:
可以給我一個securityfilterchain 使用範例
然後透過這個範例連結到其他的class
使用@Bean
ChatGPT 說:
當然可以!這裡我會提供一個完整的 Spring Boot 3 + Spring Security 6 的 SecurityFilterChain 範例,並展示如何透過 @Bean 與其他自定義類別(如 UserDetailsService、PasswordEncoder)串接。
✅ 專案結構範例
css
複製
編輯
src/
└── main/
└── java/
└── com/
└── example/
├── config/
│ └── SecurityConfig.java <-- SecurityFilterChain 配置
├── service/
│ └── CustomUserDetailsService.java
└── model/
└── User.java
✅ 1. SecurityConfig.java
java
複製
編輯
package com.example.config;
import com.example.service.CustomUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
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 {
// 核心設定:SecurityFilterChain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(login -> login.loginPage("/login").permitAll())
.logout(logout -> logout.permitAll());
return http.build();
}
// 注入自定義的 UserDetailsService
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
// 密碼編碼器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// AuthenticationManager 提供給 Login 認證流程
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
✅ 2. CustomUserDetailsService.java
java
複製
編輯
package com.example.service;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.List;
public class CustomUserDetailsService implements UserDetailsService {
// 假資料,你也可以從 DB 撈資料
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!username.equals("nico")) {
throw new UsernameNotFoundException("User not found");
}
return new User(
"nico",
"$2a$10$0YzJqOeVefUc.9Q09nPvQeQpNmUo6br6kxhZZJgIBq1E3ddt.X4X2", // bcrypt(123456)
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
}
}
✅ 3. 用瀏覽器測試 /login
打開 /login
輸入帳號:nico
密碼:123456(已 bcrypt 加密)
通過驗證後,可訪問受保護資源
如果你之後要連結到資料庫(用 JPA 讀取使用者),CustomUserDetailsService 就可以改成:
java
複製
編輯
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) {
UserEntity user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Not found"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
}
需要我幫你加上 JPA 整合版本嗎?還是你想接 JWT?我可以根據你的用途再調整。
是有關於@bean的問題
ChatGPT 說:
了解,你提到的錯誤是關於 @Bean 標註 SecurityFilterChain 時發生問題。這通常與以下幾個常見問題有關:
🔍 請先檢查這個方法定義:
java
複製
編輯
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/**").permitAll()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
✅ @Bean 方法常見錯誤排查
錯誤情況 解釋與解法
未回傳 SecurityFilterChain @Bean 方法必須明確 return http.build();
方法簽名錯誤 public SecurityFilterChain securityFilterChain(HttpSecurity http) 是必要的簽名,錯誤的參數或回傳型別都會報錯
缺少 @Configuration 或 @EnableWebSecurity Spring 不會掃描 @Bean 方法,如果這些註解沒加上
方法名稱不一致但被引用了舊名稱 確保方法名不會在其他地方錯誤地引用
其他配置類別衝突或重複定義 確保沒有多個 SecurityFilterChain Bean,否則會有重複定義錯誤
🧨 常見錯誤訊息
如果你有看到像這樣的錯誤訊息:
❌ Parameter 0 of method securityFilterChain... could not be resolved
說明 Spring 容器無法注入 HttpSecurity。這通常是:
少了 @EnableWebSecurity
你用了不正確的參數(應該是 HttpSecurity)
✅ 正確配置範例(完整版)
java
複製
編輯
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
// 可選:提供 AuthenticationManager
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
}
如果你可以提供 具體錯誤訊息 或你現在的 SecurityConfig 程式碼,我可以幫你精準對應問題點。要不要貼上來我幫你看?
你說:
可以給我一個securityfilterchain 使用範例
然後透過這個範例連結到其他的class
使用@Bean
ChatGPT 說:
當然可以!這裡我會提供一個完整的 Spring Boot 3 + Spring Security 6 的 SecurityFilterChain 範例,並展示如何透過 @Bean 與其他自定義類別(如 UserDetailsService、PasswordEncoder)串接。
✅ 專案結構範例
css
複製
編輯
src/
└── main/
└── java/
└── com/
└── example/
├── config/
│ └── SecurityConfig.java <-- SecurityFilterChain 配置
├── service/
│ └── CustomUserDetailsService.java
└── model/
└── User.java
✅ 1. SecurityConfig.java
java
複製
編輯
package com.example.config;
import com.example.service.CustomUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
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 {
// 核心設定:SecurityFilterChain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(login -> login.loginPage("/login").permitAll())
.logout(logout -> logout.permitAll());
return http.build();
}
// 注入自定義的 UserDetailsService
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
// 密碼編碼器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// AuthenticationManager 提供給 Login 認證流程
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
✅ 2. CustomUserDetailsService.java
java
複製
編輯
package com.example.service;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.List;
public class CustomUserDetailsService implements UserDetailsService {
// 假資料,你也可以從 DB 撈資料
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!username.equals("nico")) {
throw new UsernameNotFoundException("User not found");
}
return new User(
"nico",
"$2a$10$0YzJqOeVefUc.9Q09nPvQeQpNmUo6br6kxhZZJgIBq1E3ddt.X4X2", // bcrypt(123456)
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
}
}
✅ 3. 用瀏覽器測試 /login
打開 /login
輸入帳號:nico
密碼:123456(已 bcrypt 加密)
通過驗證後,可訪問受保護資源
如果你之後要連結到資料庫(用 JPA 讀取使用者),CustomUserDetailsService 就可以改成:
java
複製
編輯
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) {
UserEntity user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Not found"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
}
需要我幫你加上 JPA 整合版本嗎?還是你想接 JWT?我可以根據你的用途再調整。
你說:
還有spring boot 3用在 security config的寫法
ChatGPT 說:
非常好 👍 我來幫你整理 Spring Boot 3 + Spring Security 6 的標準 SecurityConfig 寫法,這是升級後必須學會的新風格。
✅ Spring Boot 3 安全設定(SecurityConfig)完整版範例
這個版本會展示:
不用再繼承 WebSecurityConfigurerAdapter
使用 SecurityFilterChain + @Bean
使用 requestMatchers()(取代舊的 antMatchers())
整合登入、登出、CSRF、密碼加密器、自定義使用者服務等
📄 SecurityConfig.java
java
複製
編輯
package com.example.config;
import com.example.service.CustomUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
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 {
// 核心:SecurityFilterChain 用來取代 WebSecurityConfigurerAdapter
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 如需前後端分離常會關閉
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register", "/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/dashboard", true)
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
// 提供 AuthenticationManager(通常與登入認證配合)
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
// 自定義 UserDetailsService(可替換為查資料庫)
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
// 密碼加密器:用於 encode 和 match 密碼
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
✅ 為什麼這樣寫?
舊方式(Spring Boot 2.x) 新方式(Spring Boot 3.x)
extends WebSecurityConfigurerAdapter ❌ 已移除
antMatchers(...) ❌ 改為 requestMatchers(...)
無需建立 SecurityFilterChain ✅ 需自己建一個 @Bean 回傳 http.build()
🔐 登入邏輯(後端處理)
如果你使用 Spring Security 內建表單登入(formLogin()),它會自動提供 /login POST 認證端點,除非你自己實作。
❓你可以這樣擴充:
JWT 驗證? → 替換 formLogin() 改為加上 http.addFilterBefore(...) 加入 JWT Filter。
角色判斷? → hasRole("ADMIN") 或 hasAuthority("ROLE_ADMIN")
資料庫驗證使用者? → 改寫 CustomUserDetailsService 去用 JPA 查資料
如果是在test裡面要怎麼寫
ChatGPT 說:
如果你是在 test 測試環境中使用 SecurityFilterChain + CORS + Spring Boot 3 / Security 6,你可以這樣做 👇
✅ 測試環境下的 Security 配置方式
你有兩種做法:
✅ 方法 1:在測試中啟用完整的 SecurityConfig
如果你測試的目的是整合測試(Integration Test),直接載入原本的 SecurityConfig 是最簡單的:
📄 測試類別:
java
複製
編輯
@AutoConfigureMockMvc
@SpringBootTest
@Import(SecurityConfig.class) // 或是 @ContextConfiguration(classes = SecurityConfig.class)
public class YourControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testPublicEndpoint_withCors() throws Exception {
mockMvc.perform(get("/public/test")
.header("Origin", "http://localhost:3000"))
.andExpect(status().isOk());
}
}
📝 注意:
若使用 MockMvc,它會模擬完整的 FilterChain,包含 CorsFilter
一定要記得送出 Origin header 才能觸發 CORS 機制
✅ 方法 2:自訂測試專用 Security Config(簡化版)
如果你只要測試基本 API 回傳結果,而不想跑完整認證邏輯,可提供一個測試用的 SecurityFilterChain:
📄 TestSecurityConfig.java
java
複製
編輯
@Configuration
@EnableWebSecurity
public class TestSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.cors(Customizer.withDefaults())
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("*")); // 測試階段允許全部
configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
📄 YourControllerTest.java
java
複製
編輯
@AutoConfigureMockMvc
@SpringBootTest
@Import(TestSecurityConfig.class)
public class YourControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testCorsHeadersExist() throws Exception {
mockMvc.perform(options("/public/test")
.header("Origin", "http://localhost:3000")
.header("Access-Control-Request-Method", "GET"))
.andExpect(status().isOk())
.andExpect(header().string("Access-Control-Allow-Origin", "http://localhost:3000"));
}
}
🧪 其他小技巧
加 @DirtiesContext 可以強制重建 Spring Context(用於切換 Config)
用 @TestConfiguration 可以內嵌小範圍的設定替代正式配置
如果你只測 controller 邏輯,也可用 @WebMvcTest(controller.class) + MockBean 注入假的 SecurityFilterChain 或其他依賴
想要我幫你整理一個可執行的測試專案 template 嗎?還是你希望用 WebFlux、JWT、或其他組合?可以說明你的測試目標,我幫你最佳化。