Administrator
发布于 2022-10-01 / 10532 阅读
275

Spring Security 6 配置变更与 OAuth2 接入

准备升级 Spring Security 6:配置风格全变了

Spring Security 6.0 要在 2022 年 11 月随 Spring Boot 3.0 一起 GA,但我们不想等上线了再手忙脚乱。10 月初我就拉了 6.0 的候选版本做预研,最大的冲击是:WebSecurityConfigurerAdapter 被废弃了,那套我们写了好几年的配置模板全要重写。把关键变更和 OAuth2/JWT 接法整理如下。

变更一:WebSecurityConfigurerAdapter 没了

老写法是继承适配器,重写 configure 方法:

// 老写法(Spring Security 5.x)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and().formLogin();
    }
}

6.0 里适配器被标记为废弃(后续版本移除),改为直接声明一个 SecurityFilterChain Bean,用 Lambda DSL 配置。好处是配置变显式、可组合,不再依赖继承:

// 新写法(Spring Security 6.0)
@Configuration
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();
    }
}

注意两处改名:authorizeRequestsauthorizeHttpRequestsantMatchersrequestMatchers。后者支持 Ant、MVC 和正则多种匹配,更统一。

变更二:Lambda DSL 让配置可终结

新风格用 Lambda 替代链式 .and()。老式 .and() 链式很容易漏写、嵌套错;Lambda 里每个配置块独立,IDE 能帮你检查括号闭合:

http
    .csrf(csrf -> csrf.disable())   // 无状态 API 常关 CSRF
    .sessionManagement(sm -> sm.sessionCreationPolicy(STATELESS))
    .authorizeHttpRequests(auth -> auth
        .requestMatchers("/api/public/**").permitAll()
        .anyRequest().authenticated())
    .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));

变更三:OAuth2 资源Ubuntu 服务器与 JWT 集成

我们对外暴露的 API 用 JWT 做Bearer 鉴权。6.0 里配置资源服务器读 JWT 非常简洁,关键是指定 JWT 解码器,可以从授权服务器的元数据自动获取公钥:

@Bean
public JwtDecoder jwtDecoder() {
    // 从授权服务器的 JWK Set 端点获取公钥
    return NimbusJwtDecoder
        .withIssuerLocation("https://auth.xxx.com/realms/order")
        .build();
}

// 在 filterChain 里启用
http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> {}));

拿到 Jwt 后,从 claims 里提取权限映射到 GrantedAuthority。我们自定义了一个 JwtAuthenticationConverter

@Bean
public JwtAuthenticationConverter jwtAuthConverter() {
    JwtGrantedAuthoritiesConverter conv = new JwtGrantedAuthoritiesConverter();
    conv.setAuthoritiesClaimName("roles");
    conv.setAuthorityPrefix("ROLE_");   // 让 hasRole("ADMIN") 对应 roles=["ADMIN"]
    JwtAuthenticationConverter c = new JwtAuthenticationConverter();
    c.setJwtGrantedAuthoritiesConverter(conv);
    return c;
}

实测一个小坑:6.0 默认对 JWT 的 iss 校验更严格,如果授权服务器 issuer 地址末尾带不带 / 要和 withIssuerLocation 完全一致,否则启动就 401。我们在这个细节上调试了半小时。

迁移时要查的几处

旧(5.x)新(6.0)
extends WebSecurityConfigurerAdapter声明 SecurityFilterChain Bean
authorizeRequests()authorizeHttpRequests()
antMatchers()requestMatchers()
.and() 链式Lambda DSL

小结

  • WebSecurityConfigurerAdapter 被废弃,改为声明 SecurityFilterChain Bean,配置显式可组合。
  • Lambda DSL 替代 .and(),可读性更好,IDE 友好。
  • OAuth2 资源服务器 + JWT 通过 oauth2ResourceServer().jwt() 启用,解码器从 JWK 端点自动取公钥。
  • 权限映射注意 ROLE_ 前缀与 issuer 严格匹配两个细节。

这次预研最大的感受:Security 6 不是简单改名,而是把"靠继承配置"改成了"靠组合声明"。短期要改不少模板代码,但长期看,不再有那个必须记住要 override 哪个方法的适配器基类,配置意图反而更清楚了

参考