如何在KeycloakWebSecurityConfigurerAdapter中校验用户分组
答案
KeycloakWebSecurityConfigurerAdapter 默认不直接支持用户组校验,你当前只能做角色校验的原因是:默认配置使用的SimpleAuthorityMapper只会解析Keycloak令牌中的角色字段,映射为Spring Security的权限标识,不会处理用户组字段。但你完全可以通过少量扩展配置实现用户组归属校验,不需要替换现有权限框架。
具体实现步骤
1. 配置Keycloak客户端将用户组信息注入令牌
首先在Keycloak管理后台完成配置,让登录返回的访问令牌携带用户所属组信息:
- 进入你应用对应的客户端配置页,打开Mappers标签页
- 新增一个类型为
Group Membership的映射器 - 自定义映射器名称,将Token Claim Name设置为
groups,同时勾选「Add to access token」选项,保存配置即可。后续用户登录签发的JWT令牌中就会包含当前用户的所有所属组列表。
2. 自定义权限映射器,同时加载角色和用户组权限
替换你当前使用的SimpleAuthorityMapper,自定义一个权限映射器,同时解析令牌中的角色和用户组,统一转为Spring Security可识别的GrantedAuthority。为了方便区分角色和组,可以给组对应的权限加GROUP_前缀,和角色的ROLE_前缀做区分:
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.context.SecurityContextHolder; import org.keycloak.KeycloakPrincipal; import org.keycloak.KeycloakSecurityContext; import org.keycloak.representations.AccessToken; import java.util.*; public class KeycloakGroupAuthorityMapper implements GrantedAuthoritiesMapper { private static final String ROLE_PREFIX = "ROLE_"; private static final String GROUP_PREFIX = "GROUP_"; @Override public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) { Set<GrantedAuthority> result = new HashSet<>(); // 保留原有角色映射逻辑 authorities.forEach(auth -> { if (auth instanceof org.keycloak.adapters.springsecurity.KeycloakRole) { result.add(new SimpleGrantedAuthority(ROLE_PREFIX + auth.getAuthority())); } }); // 从令牌中提取用户组信息,映射为权限 KeycloakPrincipal<KeycloakSecurityContext> principal = (KeycloakPrincipal<KeycloakSecurityContext>) SecurityContextHolder .getContext().getAuthentication().getPrincipal(); AccessToken token = principal.getKeycloakSecurityContext().getToken(); Object groupsClaim = token.getOtherClaims().get("groups"); if (groupsClaim instanceof List<?> groups) { groups.forEach(group -> { String groupName = ((String) group).replaceFirst("^/", ""); result.add(new SimpleGrantedAuthority(GROUP_PREFIX + groupName)); }); } return result; } }
修改你原有配置中的configureGlobal方法,将默认的权限映射器替换为自定义实现:
@Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); // 替换为支持组映射的权限转换器 keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new KeycloakGroupAuthorityMapper()); auth.authenticationProvider(keycloakAuthenticationProvider); }
3. 在接口权限规则中配置组校验
完成映射后,就可以直接使用Spring Security原生的hasAuthority方法配置接口的组访问权限,示例配置如下:
@Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.authorizeRequests(a-> a .antMatchers("/customers*", "/users*").hasRole("user") // 限制仅属于"vip_user"组的用户可访问/vip开头的接口 .antMatchers("/vip/**").hasAuthority("GROUP_vip_user") .anyRequest().permitAll()); }
如果你需要实现更复杂的组校验逻辑(比如同时匹配多个组、按组路径层级做权限匹配),也可以不做权限映射,直接在自定义校验方法中读取Keycloak令牌的groups字段做判断,灵活度更高。
内容的提问来源于stack exchange,提问作者Axel HK
相关产品推荐
相关产品推荐

