專案使用了SpringBoot3 ,因此 SpringSecurity也相應進行了升級 版本由5.4.5升級到了6.1.5 寫法上發生了很大的變化,最顯著的變化之一就是對 WebSecurityConfigurerAdapter
類的使用方式的改變。這個類在 Spring Security 中被廣泛用於自定義安全設定。以下是主要的差異和寫法上的變化:
廢棄 WebSecurityConfigurerAdapter
:
WebSecurityConfigurerAdapter
是實現安全設定的常用方法。使用者通過繼承這個類,並覆蓋其方法來自定義安全設定。WebSecurityConfigurerAdapter
被標記為過時(deprecated),意味著它可能在未來的版本中被移除。這一變化是為了推動使用更現代的設定方法,即使用元件式設定。使用元件式設定:
WebSecurityConfigurerAdapter
。SecurityFilterChain
bean 來設定安全規則。這種方式更加靈活,並且與 Spring Framework 的整體風格更加一致。 範例程式碼變化:
WebSecurityConfigurerAdapter
的設定框架:@Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .httpBasic(); } }
@Configuration public class SecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .httpBasic(); return http.build(); } }
專案上具體的寫法:
WebSecurityConfigurerAdapter
的設定:@Configuration @Component @EnableWebSecurity @AllArgsConstructor @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Value("${auth.whitelist:/login}") private final String[] URL_WHITELIST; private final AuthenticationFailureHandler loginFailureHandler; private final UserLoginSuccessHandler loginSuccessHandler; private final UserLogoutSuccessHandler logoutSuccessHandler; private final UserDetailsService userDetailsService; private final AccessDeniedHandler authAccessDeniedHandler; private final AuthenticationEntryPoint loginAuthenticationEntryPoint; @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean public UserAuthenticationProvider myAuthenticationProvider() { UserAuthenticationProvider userAuthenticationProvider = new UserAuthenticationProvider(userDetailsService); return userAuthenticationProvider; } @Bean JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception { JwtAuthenticationFilter jwtAuthenticationFilter2 = new JwtAuthenticationFilter(authenticationManager()); return jwtAuthenticationFilter2; } @Override protected void configure(HttpSecurity http) throws Exception { http .cors() .and() .csrf().disable() .formLogin() .loginProcessingUrl("/login") .usernameParameter("userName") .passwordParameter("password") .successHandler(loginSuccessHandler) .failureHandler(loginFailureHandler) .and() .logout() .logoutSuccessHandler(logoutSuccessHandler) //禁用session .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) //設定攔截規則 .and() .authorizeRequests() .antMatchers(URL_WHITELIST).permitAll() .anyRequest().authenticated() //例外處理器 .and() .exceptionHandling() .authenticationEntryPoint(loginAuthenticationEntryPoint) .accessDeniedHandler(authAccessDeniedHandler) .and() .addFilterAfter(jwtAuthenticationFilter(), ExceptionTranslationFilter.class); } }
@Configuration @Component @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfiguration { @Value("${bxt.auth.whitelist:/login}") private final String[] URL_WHITELIST; private final CustomerUserDetailsService customUserDetailsService; private final CustomLoginSuccessHandler loginSuccessHandler; private final CustomLoginFailureHandler loginFailureHandler; private final AccessDeniedHandler authAccessDeniedHandler; private final AuthenticationEntryPoint loginAuthenticationEntryPoint; @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); // 範例化您的 JWT 過濾器 } @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return new ProviderManager(new DaoAuthenticationProvider() {{ setUserDetailsService(customUserDetailsService); setPasswordEncoder(bCryptPasswordEncoder()); }}); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .authorizeRequests(authz -> authz .requestMatchers(URL_WHITELIST).permitAll() // 允許存取無需認證的路徑 .anyRequest().authenticated() ) .formLogin(form -> form. loginProcessingUrl("/login") .usernameParameter("username") .passwordParameter("password") .successHandler(loginSuccessHandler) .failureHandler(loginFailureHandler) ) .logout(Customizer.withDefaults()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .userDetailsService(customUserDetailsService) .exceptionHandling(exceptionHandle -> exceptionHandle .authenticationEntryPoint(loginAuthenticationEntryPoint) .accessDeniedHandler(authAccessDeniedHandler) ) .addFilterAfter(jwtAuthenticationFilter(), ExceptionTranslationFilter.class) .httpBasic(Customizer.withDefaults()); return http.build(); } }
總之,從 Spring Security 5.x 遷移到 6.x,主要的改變是從繼承 WebSecurityConfigurerAdapter
轉向定義 SecurityFilterChain
bean 的方式來設定安全性。這種變化旨在使設定更加模組化和靈活,並更好地符合 Spring 框架的整體設計哲學。