如何为Keycloak自定义JPA用户存储添加角色与组并同步至JWT
解决Keycloak JPA用户存储扩展中组/角色显示在JWT的问题
一、正确实现UserAdapter的组与角色方法
你直接在UserAdapter里定义groups和roles列表是无效的,因为Keycloak是通过调用UserModel接口的标准方法来获取用户的组和角色信息,必须重写对应方法才能让系统识别到:
1. 处理用户组
先确保你的UserEntity已和组实体建立关联(比如多对多映射),假设你有GroupEntity实体,UserEntity中包含Set<GroupEntity> groups字段。然后在UserAdapter中重写以下方法:
@Override public Set<GroupModel> getGroups() { Set<GroupModel> groupModels = new HashSet<>(); for (GroupEntity groupEntity : userEntity.getGroups()) { // 通过Keycloak会话获取对应组模型 GroupModel group = session.groups().getGroupById(realm, groupEntity.getId()); if (group != null) { groupModels.add(group); } } return groupModels; } @Override public boolean isMemberOf(GroupModel group) { return getGroups().stream().anyMatch(g -> g.getId().equals(group.getId())); }
2. 处理用户角色
同样,先让UserEntity关联角色实体(比如RoleEntity),UserEntity中包含Set<RoleEntity> roles字段。然后在UserAdapter中重写角色相关方法:
@Override public Set<RoleModel> getRoleMappings() { Set<RoleModel> roleModels = new HashSet<>(); for (RoleEntity roleEntity : userEntity.getRoles()) { RoleModel role = session.roles().getRoleById(realm, roleEntity.getId()); if (role != null) { roleModels.add(role); } } // 追加用户继承的 Realm 角色(如果需要) roleModels.addAll(getRealmRoleMappings()); return roleModels; } @Override public boolean hasRole(RoleModel role) { return getRoleMappings().stream().anyMatch(r -> r.getId().equals(role.getId())); }
二、配置Keycloak客户端,确保组/角色被写入JWT
代码实现后,还需要在Keycloak后台配置客户端,让组和角色出现在JWT令牌中:
- 进入目标客户端的Client Scopes标签,添加
roles和groups内置客户端作用域; - 或者在客户端的Mappers标签手动添加映射器:
- 角色映射:添加「User Realm Role」映射器,设置Token Claim Name为
roles,勾选「Add to ID token」和「Add to access token」; - 组映射:添加「Group Membership」映射器,设置Token Claim Name为
groups,勾选对应的Token选项;
- 角色映射:添加「User Realm Role」映射器,设置Token Claim Name为
- 确保客户端Settings标签中「Full Scope Allowed」设置为
On(若需要获取所有权限范围)。
三、验证效果
重新部署用户存储扩展,创建测试用户并分配组和角色,获取JWT令牌后解码,即可看到roles和groups的声明字段。
内容的提问来源于stack exchange,提问作者balvak okay
相关产品推荐
相关产品推荐

