How is Spring Security configured in modern versions (SecurityFilterChain bean) versus the older WebSecurityConfigurerAdapter?
Quick Answer
Older Spring Security configuration extended WebSecurityConfigurerAdapter and overrode a configure(HttpSecurity) method — deprecated since Spring Security 5.7 and removed in later versions. Modern configuration is component-based: you declare one or more @Bean methods returning a SecurityFilterChain, built by configuring an injected HttpSecurity object with a fluent, lambda-based DSL — avoiding the rigid single-inheritance constraint of the old adapter class and making it straightforward to define multiple independent filter chains for different parts of an application.
Detailed Answer
Older style (deprecated since Spring Security 5.7, removed in 6.x): security configuration was defined by extending WebSecurityConfigurerAdapter and overriding its configure(HttpSecurity http) method:
@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin();
}
}
This relied on class inheritance — a real limitation, since Java's single inheritance meant a configuration class could only extend one adapter, making it awkward to compose or define multiple independent security configurations cleanly.
Modern style (component-based, since Spring Security 5.7+): you declare a SecurityFilterChain as a plain @Bean, built via a fluent, largely lambda-based DSL applied to an injected HttpSecurity instance:
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.csrf(Customizer.withDefaults());
return http.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Advantages of the newer approach:
- No inheritance constraint — configuration is just a
@Beanmethod, composable like any other Spring configuration. - Multiple independent
SecurityFilterChainbeans are straightforward to define, each matched to a different request pattern viasecurityMatcher(...), letting different parts of an application (e.g., a stateless JWT-secured/api/**versus a session-based form-login admin console) coexist cleanly with entirely separate security rules. - More consistent, lambda-DSL style aligned with how the rest of modern Spring configuration (
WebMvcConfigurer, etc.) is typically written.
Anyone maintaining an older codebase should expect to see WebSecurityConfigurerAdapter-based configuration, but new code should always use the SecurityFilterChain @Bean approach — the adapter class is fully removed in current Spring Security major versions.