WebSecurityConfigurerAdapter Class

For years, WebSecurityConfigurerAdapter served as the cornerstone of security configuration within the Spring Security ecosystem. Whether building a greenfield application or maintaining a legacy system, Java developers routinely extended this adapter class to configure authentication and authorization rules. This article explores the core concepts of WebSecurityConfigurerAdapter, examines its traditional usage, and discusses its deprecation and modern alternatives in recent Spring Security releases.

As an adapter implementation of the WebSecurityConfigurer interface, WebSecurityConfigurerAdapter was designed to simplify custom security configurations. By extending this class, developers could override specific methods to quickly tailor security policies such as:

  • HTTP Security Interception: Defining which URL paths require protection and which remain publicly accessible.
  • Authentication Mechanisms: Setting up form-based login, HTTP Basic authentication, or token-based strategies.
  • User Details Management: Configuring UserDetailsService instances to manage user credentials and authorities.
  • Password Encoding: Specifying how passwords are securely hashed and verified using a PasswordEncoder.
    Prior to Spring Security 5.7, standard practice involved creating a configuration class that extended WebSecurityConfigurerAdapter. Below is a typical Java-based configuration demonstrating this classic approach:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 1. Configure in-memory user authentication
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin")
            .password(passwordEncoder().encode("admin123"))
            .roles("ADMIN")
            .and()
            .withUser("user")
            .password(passwordEncoder().encode("user123"))
            .roles("USER");
    }

    // 2. Configure HTTP interception rules, login, and logout
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**", "/login").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    // 3. Configure the password encoder bean
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

In this implementation, overriding the two configure methods allowed developers to manage global authentication settings and URL-based access controls within a single monolithic class.

The Shift: Why WebSecurityConfigurerAdapter Was Deprecated

With the release of Spring Boot 2.7 and Spring Security 5.7, the framework officially marked WebSecurityConfigurerAdapter as deprecated, eventually removing it entirely in Spring Security 6.0 and Spring Boot 3.0.

The primary reasons behind this architectural shift include:

  • Move Toward Component-Based Configuration: Class inheritance introduces tight coupling and limits flexibility. Modern Java design favors composition and component-based configuration models.
  • Reducing Overload Confusion: Relying on multiple overloaded configure methods with identical names often reduced code clarity and increased cognitive load.
  • Embracing Lambda Expressions: The newer configuration style fully leverages Java 8 lambdas, resulting in fluent, readable, and declarative code structures.

Modern Alternatives: Component-Based Security

Following the removal of WebSecurityConfigurerAdapter, Spring Security strongly advocates for a component-based approach. Security policies are now customized by directly registering beans such as SecurityFilterChain and UserDetailsService into the Spring Application Context.

Here is the equivalent, modern configuration rewritten using current best practices:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
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.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class ModernSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/public/**", "/login").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .permitAll()
            )
            .logout(logout -> logout
                .permitAll()
            );
        
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails admin = User.builder()
            .username("admin")
            .password(passwordEncoder.encode("admin123"))
            .roles("ADMIN")
            .build();

        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder.encode("user123"))
            .roles("USER")
            .build();

        return new InMemoryUserDetailsManager(admin, user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Conclusion

While WebSecurityConfigurerAdapter was once the heartbeat of Spring Security development, understanding its legacy mechanics is primarily useful for maintaining older codebases. For modern applications, embracing the SecurityFilterChain bean approach aligns code with contemporary functional programming paradigms and ensures seamless compatibility with the latest security enhancements in the Spring ecosystem.