Keycloak:JWT令牌中角色重复,如何移除重复角色?
解决Keycloak JWT令牌中角色重复的问题
问题原因
从你的test-realm-import.yaml配置和JWT内容可以看出,角色重复是因为角色被多次叠加分配:
- TestUser用户直接通过
realmRoles字段分配了全部7个角色 - 该用户同时属于
Administrators和Users组,这两个组又各自分配了对应的realm角色
Keycloak生成JWT时,会将用户直接分配的角色、所属组分配的角色全部合并到roles字段中,最终导致角色重复三次。
解决方案
方案一:清理重复的角色分配(推荐,从根源解决)
修改test-realm-import.yaml,移除用户直接分配的realmRoles配置——因为这些角色已经通过组分配给用户了,无需重复设置:
apiVersion: keycloak.org/v1alpha1 kind: KeycloakRealmImport metadata: name: test-realm-import namespace: keycloak spec: realm: Test enabled: true users: - username: TestUser emailVerified: false email: testuser@example.com firstName: Test lastName: User groups: - Administrators - Users clientRoles: security-admin-console: - view-Test - Test-admin - query-Test - manage-Test Test: - Test-user account: - test-role Data: - data-user # 移除重复的realmRoles配置,组已分配对应角色 attributes: aud: - security-admin-console - Test-management scope: - openid - profile - email preferredUsername: TestUser roles: - name: view-Test description: View access to Test resources - name: Test-admin description: Admin access to Test resources - name: query-Test description: Query access to Test resources - name: manage-Test description: Manage access to Test resources - name: Test-user description: User access to Test resources - name: test-role description: Basic user role - name: data-user description: Access to Data resources groups: - name: Administrators realmRoles: - view-Test - Test-admin - query-Test - manage-Test - name: Users realmRoles: - Test-user - data-user
重新导入该配置后,Keycloak只会将组分配的角色和用户的client角色合并到JWT的roles字段中,不会出现重复。
方案二:自定义令牌映射器实现去重(保留重复分配场景时使用)
如果业务需求必须保留用户直接分配和组分配的重复角色,可通过自定义脚本映射器对roles字段去重:
- 登录Keycloak管理控制台,进入Test realm
- 左侧菜单选择
Clients,打开你用来获取令牌的客户端 - 切换到
Mappers标签页,点击Create - 配置映射器:
- Name: 自定义名称(如
Unique Realm Roles) - Mapper Type:
Script Mapper - Script Type:
JavaScript - Script内容:
var uniqueRoles = []; // 获取所有realm角色(用户直接+组)并去重 user.getRealmRoleMappings().forEach(role => { if (!uniqueRoles.includes(role.getName())) { uniqueRoles.push(role.getName()); } }); // 获取所有client角色并去重加入 user.getClientRoleMappings().forEach(role => { if (!uniqueRoles.includes(role.getName())) { uniqueRoles.push(role.getName()); } }); // 将去重后的角色设置到令牌的roles字段 token.setClaim("roles", uniqueRoles); - 勾选
Add to ID token和Add to access token
- Name: 自定义名称(如
- 删除原有的
realm roles默认映射器(避免冲突)
验证修改
重新获取JWT令牌后,用以下命令解码验证:
# 假设令牌存储在token变量中 echo $token | cut -d '.' -f 2 | base64 -d | jq '.roles'
输出的角色列表应为去重后的结果。
内容的提问来源于stack exchange,提问作者Sumith
相关产品推荐
相关产品推荐

