如何在Spring Security中获取Keycloak客户端角色用于权限校验
方案1:使用Keycloak官方Spring Boot适配器(适合Spring Boot 2.6及以下版本)
第一步:修改application.yml配置
添加核心配置开关use-resource-role-mappings,开启后适配器会自动将对应client下的角色加载到Spring Security的权限列表中:
keycloak: auth-server-url: http://你的Keycloak服务地址/auth realm: 你的Realm名称 resource: myproject # 替换为你的实际client id,和JWT中resource_access的key保持一致 use-resource-role-mappings: true # 开启client角色映射的核心配置 bearer-only: true # 纯后端资源服务可开启该配置
第二步:调整权限校验规则
配置完成后原有校验逻辑可直接生效,若不需要Spring Security默认的ROLE_前缀,也可以改用hasAuthority精准匹配角色名:
private void configureMyRole(HttpSecurity http) throws Exception { http.authorizeRequests() // 两种写法二选一,和权限映射的前缀规则对应即可 // .antMatchers("/api/**").hasAnyRole("MyClientRole") .antMatchers("/api/**").hasAnyAuthority("MyClientRole") .anyRequest().permitAll(); }
方案2:使用Spring Security原生Oauth2资源服务器(Spring Boot 2.7+推荐方案,Keycloak官方已停止维护独立适配器)
Spring Security 5+原生支持JWT解析,只需要自定义权限映射逻辑即可提取client角色,不需要额外引入Keycloak适配器。
第一步:自定义权限映射器
实现JWT权限转换逻辑,同时支持提取Realm角色和Client角色:
import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; public class KeycloakGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> { // 替换为你的实际client id,和JWT中resource_access的key保持一致 private static final String CLIENT_ID = "myproject"; @Override public Collection<GrantedAuthority> convert(Jwt jwt) { List<GrantedAuthority> authorities = new ArrayList<>(); // 提取Realm角色(不需要可删除该段逻辑) Map<String, Object> realmAccess = jwt.getClaim("realm_access"); if (realmAccess != null && realmAccess.containsKey("roles")) { ((List<String>) realmAccess.get("roles")).forEach(role -> authorities.add(new SimpleGrantedAuthority(role)) ); } // 提取Client角色 Map<String, Object> resourceAccess = jwt.getClaim("resource_access"); if (resourceAccess != null && resourceAccess.containsKey(CLIENT_ID)) { Map<String, Object> clientResource = (Map<String, Object>) resourceAccess.get(CLIENT_ID); if (clientResource.containsKey("roles")) { ((List<String>) clientResource.get("roles")).forEach(role -> authorities.add(new SimpleGrantedAuthority(role)) ); } } return authorities; } }
第二步:配置JWT解析器
将自定义转换器注册到Spring Security的JWT解析流程中:
@Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(new KeycloakGrantedAuthoritiesConverter()); return converter; } private void configureMyRole(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**").hasAnyAuthority("MyClientRole") .anyRequest().permitAll() .and() // 配置原生JWT资源服务器 .oauth2ResourceServer() .jwt() .jwtAuthenticationConverter(jwtAuthenticationConverter()); }
常见注意事项
- 配置中的clientId必须和JWT中
resource_access下的客户端key完全一致,大小写敏感 - 若使用
hasRole做校验,Spring Security会自动匹配带ROLE_前缀的权限项,可根据需求在映射角色时添加此前缀,或直接使用hasAuthority精准匹配角色名 - 自定义映射逻辑可灵活控制同时保留Realm角色和Client角色,或者只保留其中一种
内容的提问来源于stack exchange,提问作者deevelop
相关产品推荐
相关产品推荐

