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

Spring+Keycloak实现角色权限控制时@PreAuthorize失效求助

问题解决:Spring Security + Keycloak 角色权限不生效

问题根源

Spring Security 默认的 JwtAuthenticationConverter 只会解析 JWT 中的 scope/scp 字段作为权限,不会自动读取 Keycloak 放在 realm_access.roles 里的角色。这就导致你的用户角色没有被加载到 Spring Security 的 Authentication 对象中,所以 @PreAuthorize 里的角色校验全部失败。

解决方案

自定义 JwtAuthenticationConverter,让它从 Keycloak 的 realm_access.roles 字段提取角色,并转换为 Spring Security 能识别的 GrantedAuthority。

修改 SecurityConfiguration 配置

添加自定义的 JwtAuthenticationConverter Bean,并在 OAuth2 资源服务器配置中指定它:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
                .oauth2ResourceServer((oauth2ResourceServer) -> 
                    oauth2ResourceServer.jwt((jwt) -> 
                        jwt.decoder(jwtDecoder())
                           // 指定自定义的JWT转换器
                           .jwtAuthenticationConverter(jwtAuthenticationConverter())
                    )
                );
        return http.build();
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri("http://[KEYCLOAK_IP]:8080/realms/my-realm/protocol/openid-connect/certs").build();
    }

    // 自定义JWT转换器,提取Keycloak的realm角色
    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        // 指定从realm_access.roles字段读取角色
        grantedAuthoritiesConverter.setAuthoritiesClaimName("realm_access.roles");
        // 给角色添加ROLE_前缀,适配hasRole()方法的默认规则
        grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

        JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
        authenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return authenticationConverter;
    }
}

对应调整@PreAuthorize注解

配置完成后,使用以下写法即可生效:

@PreAuthorize("hasRole('myrole')")
// 或者用hasAuthority,需要对应前缀
// @PreAuthorize("hasAuthority('ROLE_myrole')")

原理说明

  • setAuthoritiesClaimName("realm_access.roles"):告诉转换器去 JWT 的 realm_access.roles 数组里读取角色
  • setAuthorityPrefix("ROLE_"):给每个角色添加 ROLE_ 前缀,因为 Spring Security 的 hasRole() 方法会自动在参数前拼接 ROLE_ 去匹配权限;如果不需要前缀,可以把这个值设为空字符串,此时用 hasAuthority("myrole") 即可。

修改后,Spring Security 会将 Keycloak 角色正确加载到用户权限列表中,@PreAuthorize 的角色校验就能正常工作了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:33:21