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

Spring Security 6+Keycloak基于Realm角色的权限访问失效排查

问题排查与解决

核心错误点

1. JWT角色提取逻辑完全错误

从你的错误日志能看到,用户角色存储在JWT的顶级Roles字段(Roles=[cafeteria, obw, ROLE_obw, courseplanning]),但你的authoritiesConverter代码一直在读取realm_access.roles,以及spring-addons-confidential/spring-addons-public这两个和你业务无关的客户端角色,完全没处理实际存在的Roles字段,导致Spring Security根本获取不到用户的角色权限,直接返回403。

另外,你的实际客户端ID是po-ms(日志里aud=[po-ms]、azp=po-ms),转换器里硬编码的客户端名称完全不对,这部分代码无效。

2. hasRole()的前缀匹配问题

Spring Security的hasRole("obw")方法会自动匹配带ROLE_前缀的权限(等价于hasAuthority("ROLE_obw")),但如果转换器直接把obw转为SimpleGrantedAuthority,权限名称是obw,和hasRole()要求的ROLE_obw不匹配,也会触发403。


修正步骤

1. 修复JWT角色转换器

修改authoritiesConverter,正确读取JWT中的角色字段,并处理前缀适配:

@SuppressWarnings("unchecked")
@Bean
public Jwt2AuthoritiesConverter authoritiesConverter() {
    return jwt -> {
        // 读取JWT中实际存储角色的顶级Roles字段
        final var roles = (Collection<String>) jwt.getClaims().getOrDefault("Roles", List.of());
        
        // 为角色统一添加ROLE_前缀,适配hasRole()方法;若使用hasAuthority可跳过此步骤
        return roles.stream()
                // 避免重复添加前缀(比如你的角色中已有ROLE_obw)
                .map(role -> role.startsWith("ROLE_") ? role : "ROLE_" + role)
                .map(SimpleGrantedAuthority::new)
                .toList();
    };
}

2. 调整权限规则(二选一)

  • 若保留hasAnyRole("obw"):上面的转换器已添加前缀,无需修改filterChain中的权限配置;
  • 若不想添加前缀:将auth.requestMatchers("/thirdpath/**").hasAnyRole("obw")改为auth.requestMatchers("/thirdpath/**").hasAnyAuthority("obw")。

3. 验证Keycloak配置

从你提供的角色配置和令牌截图来看,用户确实拥有obw角色,但要确保Keycloak的客户端(po-ms)角色映射器配置正确,保证角色被写入JWT的Roles字段(如果想改用realm_access.roles,需要在Keycloak中添加对应的映射器,将Realm角色写入该字段)。


验证方法

修改后重启服务,再次请求接口,查看日志中的Granted Authorities,应该能看到ROLE_obw、ROLE_cafeteria这类权限,此时权限校验即可正常通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:45:25