
Migrating from WebSecurityConfigurerAdapter to Spring Security 6
A practical guide for Java developers migrating from WebSecurityConfigurerAdapter to Spring Security 6 and Spring Boot 3 using authorizeHttpRequests.
Migrating From WebSecurityConfigurerAdapter
For years, WebSecurityConfigurerAdapter served as the backbone of Spring Security configuration. Developers extended this class and overrode its configure methods to dictate how HTTP requests were secured. However, with the release of Spring Security 6 and Spring Boot 3, this approach has been removed in Spring Security 6.0. This is not merely a deprecation warning; it is a breaking change that forces a fundamental rethink of how security rules are composed.
This guide walks you through the structural shift from configuration inheritance to explicit bean composition, ensuring your application remains secure and maintainable.
Why the Adapter Was Removed
The WebSecurityConfigurerAdapter pattern relied on Java inheritance to inject configuration logic. While convenient for simple applications, it created significant problems as complexity grew:
- Single Configuration Constraint: Although multiple adapters could be defined using the
@Orderannotation to separate rules for/api/**and/admin/**, doing so required verbose boilerplate and careful ordering, often leading to fragile configurations. - Implicit Defaults: The adapter hid many default behaviors. Developers often didn't know what was happening under the hood because the adapter applied sensible defaults automatically.
- Testing Complexity: Mocking or testing individual security configurations was difficult because they were tightly coupled to the adapter's lifecycle.
Spring Security 6 addresses these issues by treating security configuration as a set of discrete, composable beans. The new model is explicit: if you want a security rule, you define a SecurityFilterChain bean that contains it. This shift is a core component of the spring security 6 migration strategy, moving away from fragile inheritance hierarchies toward a more robust, functional programming model. For detailed architectural reasoning, refer to the official Spring Security reference documentation on configuration changes.
In practice, this migration often surfaces hidden issues. For instance, during a recent migration of a high-throughput e-commerce platform, we encountered a NoSuchBeanDefinitionException when removing the adapter because an older custom filter relied on implicit inheritance from the parent HttpSecurity builder.
The New Pattern: SecurityFilterChain Beans
In Spring Boot 3 with Spring Security 6, the primary artifact for security configuration is the SecurityFilterChain bean. You define this bean in a @Configuration class, and Spring Boot automatically detects it and integrates it into the application’s filter chain.
Here is a practical migration example.
Old Code (Spring Security 5 / Boot 2)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin();
}
}New Code (Spring Security 6 / Boot 3)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form.permitAll());
return http.build();
}
}Mechanism Breakdown
- Bean Definition: The
@Beanannotation onsecurityFilterChainsignals to Spring that this method produces a component for the security filter chain. The framework collects all such beans and merges them into a singleFilterChainProxy. authorizeHttpRequests: This method replacesauthorizeRequests(). It takes a lambda or DSL builder to define authorization rules. TheauthorizehttprequestsDSL provides a type-safe way to define access constraints without the verbosity of previous versions.requestMatchers: This replacesantMatchers()andregexMatchers(). It provides a more consistent and type-safe way to match HTTP requests. Under the hood,requestMatchersuses Spring’sRequestMatcherinterface, allowing for more flexible matching strategies (e.g., combining path patterns with HTTP methods).- No
.and(): The old adapter required.and()to chain back to the parentHttpSecuritybuilder. In the new model, the DSL is fluent within the lambda, so no.and()is needed. You simply configure the next part of the chain directly. - Explicit Build: The
http.build()call is crucial. It finalizes the configuration and returns theSecurityFilterChaininstance. Without this, the bean would not be created.
Key Behavioral Shifts
During migration, you will encounter several specific API changes that require attention.
1. antMatchers vs. requestMatchers
The antMatchers method is deprecated and removed. Use requestMatchers instead. It supports the same Ant-style path patterns but also allows for more complex matchers.
// Old
.antMatchers("GET", "/api/**").hasRole("USER")
// New
.requestMatchers("GET", "/api/**").hasRole("USER")You can also combine matchers for more precise control. In the new DSL, you typically chain them directly within the authorizeHttpRequests lambda:
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").hasRole("USER")
.anyRequest().authenticated()
)Note that .and() is not used in the authorizeHttpRequests lambda DSL for chaining request matchers; they are chained directly. The .and() operator is reserved for moving back to the parent HttpSecurity builder to configure other aspects like form login or CSRF, not for adding more authorization rules.
2. CSRF Protection
In Spring Security 5, CSRF protection was enabled by default. In Spring Security 6, CSRF protection is still enabled by default, but the configuration is more explicit. If you are using stateless APIs (e.g., JWT), you must explicitly disable CSRF.
.csrf(csrf -> csrf.disable())3. Session Management
Session management options are now configured via the sessionManagement builder. For example, to prevent concurrent sessions:
.sessionManagement(session -> session
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
)4. Authentication Providers
Authentication providers (like DaoAuthenticationProvider) are no longer configured via configure(AuthenticationManagerBuilder). Instead, you define them as beans and inject them into the AuthenticationManager bean.
For most standard setups, Spring Boot’s auto-configuration handles the AuthenticationManager creation automatically. You typically only need to define a custom AuthenticationManager bean if you have specific requirements that deviate from the defaults, such as integrating with a custom UserDetailsService or using a non-standard PasswordEncoder. If customization is required, you can use AuthenticationConfiguration to obtain the AuthenticationManager bean or define your own AuthenticationManagerBuilder bean, which Spring will then use to construct the manager.
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}This approach leverages the existing infrastructure while allowing you to override specific behaviors if necessary.
Conclusion
Migrating from WebSecurityConfigurerAdapter is a necessary step to leverage the full capabilities of Spring Security 6 and Spring Boot 3. The new model is more verbose but significantly more powerful and predictable. By understanding the mechanism of SecurityFilterChain beans and authorizeHttpRequests, you can create secure, maintainable, and testable configurations that scale with your application’s complexity.
Start by replacing your WebSecurityConfigurerAdapter with a SecurityFilterChain bean, update all antMatchers to requestMatchers, and review your CSRF and session management settings. The learning curve is steep, but the resulting clarity is worth the effort.
Audit your current security configuration today. Identify all instances of WebSecurityConfigurerAdapter and begin the transition to the new bean-based model to ensure your application remains secure and compatible with the latest Spring Boot releases.
Related posts
OncePerRequestFilter: The Right Base Class for JWT
Learn why OncePerRequestFilter is the correct base class for JWT authentication in Spring Security, handling async dispatches and avoiding duplicate processing.
addFilterBefore and UsernamePasswordAuthenticationFilter
Learn how to use addFilterBefore to position custom filters before UsernamePasswordAuthenticationFilter in the Spring Security filter chain.
The Spring Security Filter Chain, Ordered
An examination of the Spring Security filter chain, focusing on filter order, DelegatingFilterProxy, and servlet architecture for backend engineers.