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
相关产品推荐
相关产品推荐

