Skip to content

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.

The modern approach uses bean-based configuration with SecurityFilterChain. Here's the complete, updated configuration:

java
@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:

java
@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:

java
@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:

java
@Override
protected void configure(HttpSecurity http) throws Exception {
    // Configuration code
}

New approach:

java
@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:

java
// Deprecated:
@EnableGlobalMethodSecurity(prePostEnabled = true)

// New:
@EnableMethodSecurity(prePostEnabled = true)

4. Request Matchers Update

TIP

In Spring Security 6, antMatchers() is deprecated. Use requestMatchers():

java
// Deprecated:
.antMatchers("/api/auth/**").permitAll()

// New:
.requestMatchers("/api/auth/**").permitAll()

Alternative Configuration Approaches

For better readability, use the lambda DSL style:

java
@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:

java
@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:

java
@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedMethods("*");
        }
    };
}

Migration Checklist

  1. Replace extends WebSecurityConfigurerAdapter with component-based configuration
  2. Change configure(HttpSecurity http) method to SecurityFilterChain bean
  3. Update authentication manager configuration
  4. Replace @EnableGlobalMethodSecurity with @EnableMethodSecurity
  5. Change antMatchers() to requestMatchers()
  6. Update JWT dependencies if needed
  7. 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.