You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot3.2.3基于JWT Claims(如角色)过滤请求的最优方案

基于JWT Claims(含角色)的请求过滤实现(SpringBoot 3.2.3)

1. 核心思路

直接在已配置好的SecurityFilterChain中,通过JWT携带的Claims(如角色、自定义字段)设置访问规则,无需额外复杂组件,这是最简洁的实现方式。

2. 具体实现

方式一:在SecurityFilterChain中直接配置(推荐)

假设你的JWT中角色字段为roles(若为scope或自定义字段,替换即可),直接用Spring Security的表达式或自定义判断逻辑:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            // 公开接口放行
            .requestMatchers("/public/**").permitAll()
            // 要求JWT中包含ROLE_ADMIN角色(hasRole会自动添加ROLE_前缀)
            .requestMatchers("/admin/**").hasRole("ADMIN")
            // 基于自定义Claim过滤:仅department为finance的用户可访问
            .requestMatchers("/finance/**").access((auth, context) -> {
                JwtAuthenticationToken jwtAuth = (JwtAuthenticationToken) auth;
                String dept = jwtAuth.getToken().getClaim("department");
                return new AuthorizationDecision("finance".equals(dept));
            })
            // 其余接口需认证
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt
            // 保留你已配置的audience和issuer校验逻辑
            .audienceValidator(audienceValidator())
            .issuerValidator(issuerValidator())
        ));
    return http.build();
}

// 你已实现的audience校验器示例
private OAuth2TokenValidator<Jwt> audienceValidator() {
    return new AudienceValidator(Set.of("your-target-audience"));
}

// 你已实现的issuer校验器示例
private OAuth2TokenValidator<Jwt> issuerValidator() {
    return JwtValidators.createDefaultWithIssuer("your-issuer-url");
}

方式二:绑定Claims到Authentication(复用性更强)

如果需要在多处复用Claims权限,可配置JwtAuthenticationConverter将JWT中的Claims转换为Spring Security的权限对象:

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
    // 指定JWT中角色字段的名称
    authoritiesConverter.setAuthoritiesClaimName("roles");
    // 关闭自动添加ROLE_前缀(若JWT中角色已带ROLE_则无需此配置)
    authoritiesConverter.setAuthorityPrefix("");

    JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
    converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
    return converter;
}

// 关联到SecurityFilterChain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/admin/**").hasAuthority("admin")
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt
            .jwtAuthenticationConverter(jwtAuthenticationConverter())
            .audienceValidator(audienceValidator())
            .issuerValidator(issuerValidator())
        ));
    return http.build();
}

方式三:方法级权限控制

若需要在Controller方法上做细粒度控制,先开启方法安全:

  1. 在启动类添加@EnableMethodSecurity注解
  2. 在Controller方法上使用注解:
@RestController
@RequestMapping("/admin")
public class AdminController {
    @GetMapping("/dashboard")
    @PreAuthorize("hasAuthority('admin')")
    public String getAdminDashboard() {
        return "Admin Dashboard";
    }

    // 基于自定义Claim的判断
    @GetMapping("/finance")
    @PreAuthorize("#oauth2.hasClaim('department', 'finance')")
    public String getFinanceSection() {
        return "Finance Section";
    }
}

3. 关键注意点

  • hasRole()与hasAuthority()的区别:hasRole()会自动为角色名添加ROLE_前缀,若JWT中的角色是admin而非ROLE_ADMIN,建议使用hasAuthority("admin")
  • 自定义Claims过滤:使用access()方法直接提取JWT中的Claim做判断,无需额外编写处理器,是最轻量化的方式
  • 若JWT中用scope字段表示权限,JwtGrantedAuthoritiesConverter默认会将scope=read转换为SCOPE_read权限,可直接用hasAuthority("SCOPE_read")校验

内容的提问来源于stack exchange,提问作者Smaillns

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:26:00