← 返回题目列表

Spring Security 的配置方式怎么演进的?WebSecurityConfigurerAdapter 为什么被废弃了?

中等 第 23 / 23 题 更新于 2026/07/28
SecurityFilterChainWebSecurityConfigurerAdapterLambda DSL配置

简化版

Spring Security 的配置方式经历了一次大变化:从「继承 WebSecurityConfigurerAdapter 重写方法」变成「定义 SecurityFilterChain Bean」——WebSecurityConfigurerAdapter 在 Spring Security 5.7 被废弃、6.0 被移除。旧方式:写一个类继承 WebSecurityConfigurerAdapter,重写 configure(HttpSecurity)configure(AuthenticationManagerBuilder) 等方法来配置。新方式:@Bean 定义一个 SecurityFilterChain(配置 HttpSecurityreturn http.build()),用 @Bean 定义 UserDetailsServicePasswordEncoder 等组件。为什么废弃:① 继承的方式不够灵活(一个应用只能有一个 Adapter,难以配置多条过滤器链);② 基于组件(Bean)的方式更符合 Spring 的「组合优于继承」理念——把各配置项声明成 Bean,更清晰、可组合、能定义多个 SecurityFilterChain(按路径匹配不同安全规则)。同时的另一个变化是「Lambda DSL」:配置从链式的 .and() 风格改成 Lambda 风格(http.authorizeHttpRequests(auth -> auth...)),更清晰、不用 .and() 连接。核心:新版用 SecurityFilterChain Bean + 组件 Bean + Lambda DSL,替代旧的继承 Adapter 方式。

详细版

旧方式 vs 新方式

维度旧方式(Adapter)新方式(Bean)
配置类继承 WebSecurityConfigurerAdapter定义 SecurityFilterChain Bean
配置方法重写 configure(HttpSecurity)@Bean SecurityFilterChain(HttpSecurity)
用户/密码重写 configure(AuthManagerBuilder)@Bean UserDetailsService/PasswordEncoder
多条链难(一个 Adapter)易(多个 SecurityFilterChain Bean,@Order)
风格链式 .and()Lambda DSL
状态5.7 废弃、6.0 移除现行推荐
// ❌ 旧方式(已废弃)
@Configuration
public class OldConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and().formLogin();
    }
}

// ✅ 新方式(Spring Security 5.7+/6)
@Configuration
@EnableWebSecurity
public class NewConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth       // Lambda DSL
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated())
            .formLogin(Customizer.withDefaults());
        return http.build();                          // 返回 SecurityFilterChain Bean
    }

    @Bean
    public UserDetailsService userDetailsService() { ... }   // 组件也是 Bean

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

⚠️ 理解这个演进的关键,是「从继承到组合」的设计理念转变——WebSecurityConfigurerAdapter 的「继承」方式有个硬伤:一个应用通常只能有一个 Adapter,很难配置「多条过滤器链」(比如「/api/** 用 JWT 无状态、其他用 Session 表单登录」这种「不同路径不同安全规则」的需求,用 Adapter 很别扭)。新的 SecurityFilterChain Bean 方式,因为是 Bean,可以定义多个——每个 SecurityFilterChainsecurityMatcher 匹配不同的路径、配不同的规则,再用 @Order 控制优先级,天然支持多条链。这就是「组合优于继承」的体现:把配置声明成可组合的 Bean,比强制继承一个基类更灵活。面试注意:如果还在用 WebSecurityConfigurerAdapter,是过时的写法(Spring Boot 3 / Spring Security 6 里已经没有这个类了);新代码要用 SecurityFilterChain Bean + Lambda DSL。

完整版教学

一、旧方式:继承 WebSecurityConfigurerAdapter

先看旧的配置方式:

旧方式(Spring Security 5.7 之前):
  写一个配置类,继承 WebSecurityConfigurerAdapter
  重写它的 configure 方法来配置:

  @EnableWebSecurity
  public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // 配置 HTTP 安全(授权规则、登录等)
    protected void configure(HttpSecurity http) {
      http.authorizeRequests()...
    }
    // 配置认证(用户、密码)
    protected void configure(AuthenticationManagerBuilder auth) {
      auth.userDetailsService(...).passwordEncoder(...);
    }
    // 配置 web 安全(忽略静态资源等)
    protected void configure(WebSecurity web) { ... }
  }

特点:
  通过"重写方法"来配置
  一个 Adapter 类集中配置所有安全

问题:
  ① 继承——只能有一个(或有限个)Adapter,难配多条链
  ② 不够灵活——配置耦合在一个类的方法里
  ③ 不符合 Spring 的"组合优于继承"理念

所以这是"过时"的方式(5.7 废弃、6.0 移除)

旧方式(Spring Security 5.7 前):写配置类继承 WebSecurityConfigurerAdapter、重写 configure 方法configure(HttpSecurity) 配授权/登录、configure(AuthenticationManagerBuilder) 配用户/密码、configure(WebSecurity) 忽略静态资源)。特点:通过重写方法配置、一个 Adapter 集中配所有安全。问题:① 继承只能有一个 Adapter 难配多条链、② 不够灵活(配置耦合在一个类)、③ 不符合组合优于继承。所以过时(5.7 废弃、6.0 移除)。理解「旧方式:继承 WebSecurityConfigurerAdapter 重写 configure 方法(HttpSecurity 配授权/AuthManagerBuilder 配用户);问题:继承只能一个难配多条链/不灵活/不符合组合优于继承;5.7 废弃 6.0 移除」,就理解了旧方式和它的问题。

二、新方式:SecurityFilterChain Bean

新方式用 SecurityFilterChain Bean:

新方式(Spring Security 5.7+/6):
  不继承任何类,用 @Bean 定义 SecurityFilterChain

  @Configuration
  @EnableWebSecurity
  public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
      http.authorizeHttpRequests(auth -> auth
          .requestMatchers("/admin/**").hasRole("ADMIN")
          .anyRequest().authenticated())
        .formLogin(Customizer.withDefaults());
      return http.build();   // ★ 返回 SecurityFilterChain
    }

    @Bean  // 用户、密码等组件也是 Bean
    public UserDetailsService userDetailsService() { ... }
    @Bean
    public PasswordEncoder passwordEncoder() { ... }
  }

变化点:
  ① 配置类不再继承 WebSecurityConfigurerAdapter
  ② 用 @Bean 定义 SecurityFilterChain(配置 HttpSecurity 后 build)
  ③ UserDetailsService、PasswordEncoder、AuthenticationManager 等
     都定义成独立的 @Bean
  → 从"重写方法"变成"定义 Bean"

好处:
  ① 组合优于继承——各配置项是独立的 Bean,清晰、可组合
  ② 能定义多个 SecurityFilterChain(多条链)
  ③ 更符合 Spring 的编程模型(一切皆 Bean)

新方式(5.7+/6):不继承任何类,用 @Bean 定义 SecurityFilterChainfilterChain(HttpSecurity http) 配置后 return http.build()),UserDetailsService/PasswordEncoder/AuthenticationManager 也都定义成独立 @Bean。变化点:① 不再继承 Adapter、② @Bean 定义 SecurityFilterChain、③ 组件都是 Bean(从「重写方法」变「定义 Bean」)。好处:组合优于继承(各配置项独立 Bean 清晰可组合)、能定义多条链、符合 Spring 一切皆 Bean。理解「新方式:不继承、@Bean 定义 SecurityFilterChain(配置 HttpSecurity 后 build)、组件都是独立 Bean;从重写方法变定义 Bean;好处组合优于继承/能多条链/符合 Spring 模型」,就掌握了新方式。

三、Lambda DSL

配置风格也从链式 .and() 变成 Lambda DSL:

旧风格(链式 .and()):
  http.authorizeRequests()
      .antMatchers("/admin").hasRole("ADMIN")
      .anyRequest().authenticated()
      .and()                    // 用 .and() 连接不同配置块
      .formLogin()
      .and()
      .csrf().disable();

新风格(Lambda DSL):
  http.authorizeHttpRequests(auth -> auth
          .requestMatchers("/admin").hasRole("ADMIN")
          .anyRequest().authenticated())
      .formLogin(Customizer.withDefaults())
      .csrf(csrf -> csrf.disable());

变化:
  每个配置块用一个 Lambda(配置该块的细节)
  → 不用 .and() 连接(Lambda 自然分隔了各配置块)
  → 更清晰(每个块的配置在自己的 Lambda 里)

方法名变化(配套):
  authorizeRequests → authorizeHttpRequests(新的授权配置)
  antMatchers → requestMatchers(新的路径匹配)

为什么 Lambda DSL 更好:
  ① 结构清晰——每个配置块独立(Lambda 内)
  ② 不用记 .and()(旧方式容易漏 .and() 或搞错层级)
  ③ 更符合现代 Java 的 Lambda 风格

Customizer.withDefaults():用默认配置该块(如 formLogin 用默认)

所以新配置 = SecurityFilterChain Bean + Lambda DSL

配置风格从链式 .and() 变成 Lambda DSL:旧风格用 .and() 连接不同配置块(authorizeRequests()...and().formLogin()),新风格每个配置块用一个 LambdaauthorizeHttpRequests(auth -> auth...)formLogin(Customizer.withDefaults())csrf(csrf -> csrf.disable())),不用 .and() 连接(Lambda 自然分隔)。配套方法名变化:authorizeRequestsauthorizeHttpRequestsantMatchersrequestMatchers。好处:结构清晰(每块独立)、不用记 .and()、符合现代 Lambda 风格。理解「Lambda DSL:每个配置块用一个 Lambda 不用.and()连接(旧风格 and 连接易漏)、方法名变化 authorizeHttpRequests/requestMatchers、结构清晰;新配置=SecurityFilterChain Bean+Lambda DSL」,就掌握了 Lambda DSL。

四、多条过滤器链

新方式的一大优势是「支持多条过滤器链」:

需求:不同路径用不同安全规则
  /api/** → JWT 无状态认证(STATELESS,不用 Session)
  其他 → Session 表单登录

旧方式(Adapter)的难题:
  一个 Adapter 难以配置"两套完全不同的安全规则"
  (虽然有多个 Adapter 的办法,但别扭)

新方式(多个 SecurityFilterChain Bean):
  定义两个 SecurityFilterChain Bean,各配各的:

  @Bean @Order(1)
  public SecurityFilterChain apiChain(HttpSecurity http) {
    http.securityMatcher("/api/**")           // 只匹配 /api/**
        .authorizeHttpRequests(...)
        .sessionManagement(s -> s.sessionCreationPolicy(STATELESS))  // JWT
        .addFilter(jwtFilter);
    return http.build();
  }

  @Bean @Order(2)
  public SecurityFilterChain webChain(HttpSecurity http) {
    http.authorizeHttpRequests(...)           // 其他路径
        .formLogin(...);                       // Session 表单登录
    return http.build();
  }

关键:
  ① securityMatcher:这条链匹配哪些路径
  ② @Order:多条链的优先级(先匹配的先用)
  → 请求来了,按 @Order 顺序找第一条 securityMatcher 匹配的链

所以新方式天然支持多条链(各路径不同规则)
  → 这是"组合优于继承"的直接好处

新方式的一大优势是「支持多条过滤器链」——需求如「/api/** 用 JWT 无状态、其他用 Session 表单登录」。旧方式(Adapter)难配两套规则新方式定义多个 SecurityFilterChain Bean:用 securityMatcher 匹配不同路径、@Order 控制优先级(请求来了按 @Order 找第一条 securityMatcher 匹配的链)。这是「组合优于继承」的直接好处。理解「新方式支持多条链:定义多个 SecurityFilterChain Bean、securityMatcher 匹配不同路径、@Order 控制优先级(请求按 Order 找第一条匹配的链);旧 Adapter 难配多套规则;组合优于继承的好处」,就掌握了多条过滤器链。

五、AuthenticationManager 的获取

新方式下 AuthenticationManager 的获取也变了:

旧方式获取 AuthenticationManager:
  重写 authenticationManagerBean() 暴露它
  @Override @Bean
  public AuthenticationManager authenticationManagerBean() {
    return super.authenticationManagerBean();
  }

新方式获取 AuthenticationManager:
  ① 从 AuthenticationConfiguration 拿:
     @Bean
     public AuthenticationManager authManager(
         AuthenticationConfiguration config) throws Exception {
       return config.getAuthenticationManager();
     }
  ② 或自己构造 ProviderManager(配置多个 Provider):
     @Bean
     public AuthenticationManager authManager(...) {
       return new ProviderManager(provider1, provider2);
     }

什么时候需要 AuthenticationManager:
  自定义登录接口(自己调 authenticationManager.authenticate)
  自定义认证方式(配置多个 AuthenticationProvider)
  → 需要拿到 AuthenticationManager 来用

其他组件也是 Bean:
  UserDetailsService、PasswordEncoder、
  AuthenticationProvider、SecurityFilterChain
  → 全部 @Bean 定义、Spring 自动组装

所以新方式一切皆 Bean:配置项都是 Bean、Spring 组装

新方式下 AuthenticationManager 的获取也变了:旧方式重写 authenticationManagerBean()新方式从 AuthenticationConfigurationconfig.getAuthenticationManager())或自己构造 ProviderManager(配多个 Provider)。什么时候需要:自定义登录接口(自己调 authenticate)、自定义认证方式(多个 Provider)。其他组件(UserDetailsService/PasswordEncoder/AuthenticationProvider/SecurityFilterChain)也全部 @Bean 定义、Spring 自动组装。理解「新方式获取 AuthenticationManager:从 AuthenticationConfiguration 拿或自己构造 ProviderManager;需要时:自定义登录接口/多个 Provider;新方式一切皆 Bean(组件都@Bean、Spring 组装)」,就掌握了 AuthenticationManager 的获取。

六、迁移与实践

总结从旧到新的迁移和实践:

迁移要点(旧 → 新):
  ① 配置类去掉 extends WebSecurityConfigurerAdapter
  ② configure(HttpSecurity) → @Bean SecurityFilterChain(return http.build())
  ③ configure(AuthManagerBuilder) → @Bean UserDetailsService + PasswordEncoder
  ④ configure(WebSecurity) 忽略静态资源
     → SecurityFilterChain 里 requestMatchers(...).permitAll()
       或 WebSecurityCustomizer Bean
  ⑤ authorizeRequests → authorizeHttpRequests
     antMatchers → requestMatchers
  ⑥ 链式 .and() → Lambda DSL
  ⑦ 需要 AuthenticationManager → 从 AuthenticationConfiguration 拿

实践建议:
  ① 新项目直接用 SecurityFilterChain Bean + Lambda DSL
  ② 老项目(还用 Adapter)逐步迁移(6.0 已强制)
  ③ 多路径不同规则 → 多个 SecurityFilterChain + securityMatcher + @Order
  ④ 组件都定义成 Bean(清晰、可测、可组合)

版本对应:
  Spring Security 5.7:废弃 WebSecurityConfigurerAdapter
  Spring Security 6.0(Spring Boot 3):移除,只能用新方式

核心总结:
  从"继承 WebSecurityConfigurerAdapter 重写方法"
  到"定义 SecurityFilterChain Bean + 组件 Bean + Lambda DSL"
  原因:组合优于继承(更灵活、支持多条链、符合 Spring 模型)

迁移要点(旧→新):去掉 extends Adapter、configure(HttpSecurity)@Bean SecurityFilterChainconfigure(AuthManagerBuilder)@Bean UserDetailsService+PasswordEncoderauthorizeRequestsauthorizeHttpRequestsantMatchersrequestMatchers、链式 .and()→Lambda DSL、需要 AuthenticationManager 从 AuthenticationConfiguration 拿。实践:新项目直接用新方式、老项目逐步迁移(6.0 强制)、多路径用多个 SecurityFilterChain、组件都定义成 Bean。版本:5.7 废弃、6.0 移除。理解「迁移:去掉继承/configure 变@Bean/方法名变化/and 变 Lambda/AuthManager 从 Config 拿;实践:新项目用新方式/老项目迁移/多路径多条链/组件都 Bean;5.7 废弃 6.0 移除」,就掌握了迁移和实践。

记忆钩子:「Spring Security 配置演进:旧方式(继承 WebSecurityConfigurerAdapter 重写 configure 方法)→新方式(定义 SecurityFilterChain Bean:@Bean filterChain(HttpSecurity)配置后 return http.build()、组件 UserDetailsService/PasswordEncoder 都@Bean);WebSecurityConfigurerAdapter 5.7 废弃 6.0 移除;★为什么废弃:继承方式一个应用只能一个 Adapter 难配多条链、组合优于继承(SecurityFilterChain 是 Bean 可定义多个用 securityMatcher 匹配不同路径+@Order 控制优先级);同时 Lambda DSL:每个配置块用 Lambda 不用.and()连接(authorizeHttpRequests(auth->auth…))、方法名 authorizeRequests→authorizeHttpRequests/antMatchers→requestMatchers;AuthenticationManager 从 AuthenticationConfiguration 拿」

七、常见误区与追问

  • 误区:现在还用 WebSecurityConfigurerAdapter 配置 Spring Security。 已废弃——Spring Security 5.7 废弃、6.0(Spring Boot 3)移除了这个类;新方式是定义 SecurityFilterChain Bean(不继承任何类)+ 组件 Bean + Lambda DSL;用 Adapter 是过时写法,Spring Boot 3 里根本没这个类。
  • 误区:SecurityFilterChain 和 WebSecurityConfigurerAdapter 只是名字不同。 理念不同——Adapter 是「继承+重写方法」(一个应用一个 Adapter、难配多条链);SecurityFilterChain 是「定义 Bean」(可定义多个、用 securityMatcher 匹配不同路径、@Order 控制优先级,天然支持多条链);是「组合优于继承」的转变。
  • 误区:新旧配置的方法名一样。 有变化——authorizeRequests → authorizeHttpRequests、antMatchers → requestMatchers;还有配置风格从链式 .and() 变成 Lambda DSL(authorizeHttpRequests(auth -> auth…));迁移时要一起改。
  • 误区:Lambda DSL 只是写法好看,没实质区别。 有实质好处——每个配置块用独立的 Lambda(配置该块的细节),不用 .and() 连接(旧方式容易漏 .and() 或搞错层级导致配置错误);结构更清晰、每个块的配置在自己的作用域里、不易出错。
  • 追问:WebSecurityConfigurerAdapter 为什么被废弃? 主要因为「继承」方式不够灵活——一个应用通常只能有一个 WebSecurityConfigurerAdapter,很难配置多条过滤器链(不同路径用不同安全规则,如 /api/** 用 JWT 无状态、其他用 Session 表单登录);新的 SecurityFilterChain Bean 方式因为是 Bean,可以定义多个,每个用 securityMatcher 匹配不同路径、@Order 控制优先级,天然支持多条链;这是「组合优于继承」理念的体现,把配置声明成可组合的 Bean 比强制继承基类更灵活、更符合 Spring 的编程模型。
  • 追问:新方式怎么配置多条过滤器链(不同路径不同规则)? 定义多个 SecurityFilterChain Bean,每个用 securityMatcher(…) 声明它匹配哪些路径、配置各自的安全规则,用 @Order 控制优先级;请求到来时,Spring Security 按 @Order 顺序找第一条 securityMatcher 匹配的链来处理;比如 @Order(1) 的链匹配 /api/**(配 JWT 无状态)、@Order(2) 的链匹配其他(配 Session 表单登录);这是新方式相比旧 Adapter 的一大优势。
  • 追问:新方式下怎么获取 AuthenticationManager? 旧方式重写 authenticationManagerBean() 暴露;新方式从 AuthenticationConfiguration 拿——注入 AuthenticationConfiguration,调 config.getAuthenticationManager() 返回并定义成 @Bean;或者自己构造 ProviderManager(传入多个 AuthenticationProvider)定义成 @Bean;需要 AuthenticationManager 的场景是自定义登录接口(自己调 authenticate)或配置多种认证方式(多个 Provider)。

八、加强记忆

Spring Security 配置方式演进:从「继承 WebSecurityConfigurerAdapter 重写方法」变成「定义 SecurityFilterChain Bean」WebSecurityConfigurerAdapter 5.7 废弃、6.0(Spring Boot 3)移除)。旧方式:写类继承 WebSecurityConfigurerAdapter、重写 configure(HttpSecurity)/configure(AuthenticationManagerBuilder) 等。新方式@Bean 定义 SecurityFilterChain(配置 HttpSecurityreturn http.build()),UserDetailsService/PasswordEncoder/AuthenticationManager 等都定义成独立 @Bean为什么废弃继承方式一个应用只能有一个 Adapter、难配多条链;新的 Bean 方式符合「组合优于继承」——SecurityFilterChain 是 Bean 可定义多个(用 securityMatcher 匹配不同路径、@Order 控制优先级,天然支持多条链,如 /api/** 用 JWT、其他用 Session)。同时的另一个变化是 Lambda DSL:从链式 .and() 改成 Lambda 风格(authorizeHttpRequests(auth -> auth...)),不用 .and() 连接、更清晰;配套方法名变化(authorizeRequestsauthorizeHttpRequestsantMatchersrequestMatchers)。AuthenticationManagerAuthenticationConfiguration 获取config.getAuthenticationManager())。一句话「Spring Security 配置从继承 WebSecurityConfigurerAdapter(5.7 废弃 6.0 移除)变成定义 SecurityFilterChain Bean(return http.build())+组件 Bean;废弃因继承难配多条链、组合优于继承(SecurityFilterChain 可定义多个+securityMatcher 匹配路径+@Order);Lambda DSL 替代.and()链式;AuthenticationManager 从 AuthenticationConfiguration 拿」。