Migrating from WebSecurityConfigurerAdapter to SecurityFilterChain in Spring Security
With the deprecation of WebSecurityConfigurerAdapter
in Spring Security 5.7, developers need to adopt a component-based configuration approach. This article provides a comprehensive guide to migrating your Spring Security configuration while avoiding common pitfalls.
Problem Statement
The traditional approach to Spring Security configuration extended WebSecurityConfigurerAdapter
, but this class is now deprecated. Many developers encounter the error:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration':
Unsatisfied dependency expressed through method 'setFilterChains' parameter 0
This error typically occurs when there's a circular dependency or misconfiguration in the authentication manager setup.
Recommended Solution
The modern approach uses bean-based configuration with SecurityFilterChain
. Here's the complete, updated configuration:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
@Autowired
UsuariService userDetailsService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeHttpRequests()
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/test/**").permitAll()
.requestMatchers("/api/v1/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
WARNING
Note the method name change: authorizeRequests()
is deprecated in Spring Security 6. Use authorizeHttpRequests()
instead.
Key Changes Explained
1. Authentication Manager Configuration
Old approach:
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
New approach:
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
The authentication manager is now automatically configured by Spring using the UserDetailsService
and PasswordEncoder
beans you provide.
2. HttpSecurity Configuration
Old approach:
@Override
protected void configure(HttpSecurity http) throws Exception {
// Configuration code
}
New approach:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// Configuration code
return http.build();
}
3. Method Security Annotation Update
INFO
As of Spring Security 6, @EnableGlobalMethodSecurity
is deprecated. Use @EnableMethodSecurity
instead:
// Deprecated:
@EnableGlobalMethodSecurity(prePostEnabled = true)
// New:
@EnableMethodSecurity(prePostEnabled = true)
4. Request Matchers Update
TIP
In Spring Security 6, antMatchers()
is deprecated. Use requestMatchers()
:
// Deprecated:
.antMatchers("/api/auth/**").permitAll()
// New:
.requestMatchers("/api/auth/**").permitAll()
Alternative Configuration Approaches
Using Lambda DSL (Recommended)
For better readability, use the lambda DSL style:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.exceptionHandling(exception -> exception
.authenticationEntryPoint(unauthorizedHandler))
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/test/**").permitAll()
.requestMatchers("/api/v1/**").permitAll()
.anyRequest().authenticated())
.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
Custom Authentication Manager
If you need more control over the authentication manager:
@Bean
public AuthenticationManager authenticationManager(UserDetailsService customUserDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(customUserDetailsService);
authProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(List.of(authProvider));
}
Common Issues and Solutions
Circular Dependency Resolution
If you encounter circular dependency issues, ensure you're not manually building the AuthenticationManager
in multiple places. The recommended approach is to rely on Spring's AuthenticationConfiguration
.
JWT Library Updates
If you're using JWT, note that the jjwt
dependency has changed. Update your dependencies according to the latest jjwt documentation.
CORS Configuration
For CORS configuration, you can use a separate bean:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*");
}
};
}
Migration Checklist
- Replace
extends WebSecurityConfigurerAdapter
with component-based configuration - Change
configure(HttpSecurity http)
method toSecurityFilterChain
bean - Update authentication manager configuration
- Replace
@EnableGlobalMethodSecurity
with@EnableMethodSecurity
- Change
antMatchers()
torequestMatchers()
- Update JWT dependencies if needed
- Test all security endpoints thoroughly
By following these steps, you'll successfully migrate from the deprecated WebSecurityConfigurerAdapter
to the modern bean-based configuration approach in Spring Security.