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

Spring Boot多服务JWT认证403权限错误求助

问题排查与修复方案

问题背景

开发包含3个Spring Boot服务的项目:

  • users服务提供用户注册、登录公开端点,生成JWT Token
  • plans服务的多数端点要求Marketing Director角色权限,携带JWT访问时返回403 Forbidden,JWT解析显示角色正确但提示签名无效,所有服务使用相同RSA密钥对

核心问题与修复步骤

1. 自定义JWT权限转换器未生效

Plans服务的SecurityConfig中定义了jwtAuthenticationConverter Bean,但未绑定到OAuth2资源服务器的JWT配置,导致角色转换逻辑未执行。

修复代码(Plans服务SecurityConfig):

@Override
protected void configure(HttpSecurity http) throws Exception {
    // ... 原有配置 ...

    // 绑定自定义转换器到JWT资源服务器
    http.authorizeRequests()
        // ... 原有授权规则 ...
        .and().oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
        );
}

2. JWT角色声明格式不匹配转换器预期

Users服务生成JWT时,将角色用空格拼接为单个字符串存入roles Claim,但默认转换器会把整个字符串当作单一权限,无法正确解析为角色。

修复方案二选一:

方案A:修改Users服务,将角色存入列表

// 替换原scope生成逻辑
final List<String> roles = authentication.getAuthorities().stream()
    .map(GrantedAuthority::getAuthority)
    .collect(Collectors.toList());

// 构建JWT声明时传入列表
final JwtClaimsSet claims = JwtClaimsSet.builder()
    .issuer("example.io")
    .issuedAt(now)
    .expiresAt(now.plusSeconds(expiry))
    .subject(format("%s,%s", user.getId(), user.getUsername()))
    .claim("roles", roles) // 用列表替代字符串
    .build();

方案B:自定义转换器分割字符串角色

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    return new JwtAuthenticationConverter() {
        @Override
        protected Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {
            String rolesString = jwt.getClaimAsString("roles");
            if (rolesString == null) {
                return Collections.emptyList();
            }
            // 分割空格分隔的角色,添加ROLE_前缀
            return Arrays.stream(rolesString.split(" "))
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());
        }
    };
}

3. hasRole方法的权限前缀冲突

Spring Security的hasRole("X")会自动拼接ROLE_前缀,而你的角色包含空格,建议直接使用hasAuthority明确指定完整权限名,避免歧义。

修改Plans服务授权规则:

.antMatchers("/api/plan/**").hasAuthority("ROLE_Marketing Director")

4. 签名无效的验证点

  • 确认配置文件中的RSA密钥格式正确,YAML配置需用|保留换行:
    jwt:
      public-key: |
        -----BEGIN PUBLIC KEY-----
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
        ...
        -----END PUBLIC KEY-----
    
  • 检查Users和Plans服务的密钥配置完全一致,无复制错误或格式丢失。

5. 优化Users服务安全配置(可选)

取消@EnableGlobalMethodSecurity的注释,便于后续方法级权限控制:

@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)

内容的提问来源于stack exchange,提问作者Rui Santelmo- 1210861

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:37:02