Keycloak 为什么需要自定义协议 Mapper?

发布于:2025-07-10 ⋅ 阅读:(20) ⋅ 点赞:(0)

Keycloak 中,自定义协议 Mapper(Custom Protocol Mapper) 是一种非常强大的机制,它允许你 动态地将用户属性、客户端属性或其他信息注入到 Token(ID Token 或 Access Token)中


🧠 为什么需要自定义协议 Mapper?

Keycloak 默认的(访问) Token 只包含一些基础字段,如 subpreferred_usernameemail 等。但在实际业务中,我们往往希望:

  • 把用户的 租户 ID(tenant_id)
  • 用户所属的 组织名称(organization_name)
  • 用户的角色权限(roles
  • 客户端相关的元数据(client_metadata
  • 自定义业务字段(如部门、职位、区域等)

通过 自定义协议 Mapper,你可以灵活控制(访问) Token 的内容,满足后端服务 鉴权、路由、多租户管理 等需求。


✅ 场景举例

场景 描述
多租户系统 将用户的 tenant_id 注入 Token,便于下游服务识别归属租户
微服务认证 在 Token 中添加 department, location, role_level 等字段用于访问控制
第三方集成 向特定 client 发放 token 时添加 integration_keyapi_key
动态权限 根据用户角色或属性生成 permissions 字段

🔧 配置步骤:如何创建一个自定义协议 Mapper

以下以向 Token 添加 tenant_id 字段为例,介绍如何配置一个自定义协议 Mapper

步骤 1:进入 Client Scopes 页面

  1. 登录 Keycloak 管理后台
  2. 进入对应 Realm
  3. 左侧菜单点击 Client Scopes
  4. 选择你要绑定 MapperScope(通常为 profileyour_clientdefault scope

步骤 2:添加新的 Mapper

  1. 点击页面上的 Add mapper > By configuration
  2. 选择 Mapper 类型:
    • 推荐使用 User Attribute Mapper(将用户属性注入 Token

步骤 3:填写 Mapper 表单(以 User Attribute 为例)

字段 说明
Name tenant_id Mapper 名称(任意命名)
Mapper Type User Attribute 表示从用户属性中提取数据
User Attribute tenant_id 用户实体中的属性名(需提前设置好)
Token Claim Name tenant_id 最终在 Token 中的字段名
Claim Value Type String / JSON / Long 数据类型
Add to ID token ✅ Yes 是否写入 ID Token
Add to access token ✅ Yes 是否写入 Access Token
Friendly Name 可选 显示用名称
Description 可选 描述

✅ 保存后,该字段将在后续签发的 Token 中自动出现。


📦 示例:Token 输出效果

  • 假设某用户有如下属性:
{
  "username": "john_doe",
  "attributes": {
    "tenant_id": "tenant_001",
    "department": "IT"
  }
}
  • 配置好 Mapper 后,获取的 Token 将包含:
{
  "exp": 1718000000,
  "iat": 1718000000,
  "jti": "abc123...",
  "iss": "https://keycloak.example.com/auth/realms/myrealm",
  "aud": "my-client",
  "sub": "user-uuid",
  "tenant_id": "tenant_001",   ← 新增字段
  "department": "IT"           ← 可选新增字段
}

🧩 其他常见 Mapper 类型(可选)

除了 User Attribute,还有多种类型的 Mapper 可供使用:

Mapper 类型 用途说明
User Attribute 从用户属性映射字段
Role Name 显示当前用户的所有角色
Group Membership 显示用户所属组(group)
Hardcoded claim 固定值字段(如 environment=production)
Script Mapper 使用 JavaScript 脚本动态构造字段(高级)
Audience 添加 audience 字段
Attribute Statement SAML 协议相关

如果你需要更复杂的逻辑(比如根据用户角色动态生成权限列表),可以使用 Script Mapper


🧪 Script Mapper 示例(高级用法)

场景:根据用户角色生成权限字段 permissions

1. 创建 Script Mapper
  • Mapper TypeScript Mapper
  • Namepermissions-mapper
  • Script
// 获取用户所有角色
var roles = user.getRealmRoleMappings();
var permissions = [];

if (roles) {
    for (var i = 0; i < roles.size(); i++) {
        var role = roles.get(i);
        if (role.getName().startsWith("perm_")) {
            permissions.push(role.getName().replace("perm_", ""));
        }
    }
}

$token.setOtherClaims("permissions", permissions);
2. 效果(Token 中新增字段)
{
  "permissions": ["read:data", "write:data", "delete:user"]
}

🧰 如何给 Service Account 用户添加属性(client_credentials 模式)

如果你使用的是 client_credentials 模式,你需要给 Service Account 用户 添加属性:

步骤:

  1. 打开你的 Client 设置页
  2. 点击 Service Account Settings
  3. 开启 Service Account Enabled
  4. 查看 Service Account 用户(通常是 service-account-{client-id}
  5. 编辑该用户,在 Attributes 中添加 tenant_id: tenant_001
  6. 再次请求 Token,你应该能在 Token 中看到这个字段

🧩 Mapper 的作用范围

Mapper 可以绑定到不同作用域:

作用域 说明
Realm-Level Mappers 对整个 Realm 下的所有 Token 生效
Client-Level Mappers 仅对该 Client 签发的 Token 生效
Client Scope Mappers 绑定到某个 Scope,只有请求该 Scope 时才生效

例如:

  • 你想让所有 Client 都带上 tenant_id → 放到 Realm-Level Mapper
  • 你只想让特定 Client 带上 tenant_id → 放到 Client-Level Mapper
  • 你只想在某些 Scope 下带 tenant_id → 放到 Client Scope Mapper

🛠 常见问题排查

问题 解决方法
Token 中没有新字段 检查是否已启用 Mapper 并正确绑定 Scope
用户属性为空 确保用户确实设置了该属性
Service Account 没有属性 确认是 Service Account 用户本身设置了属性
Mapper 不生效 清除缓存并重新获取 Token
Mapper 写入了错误位置 检查是否勾选了 “Add to ID Token”“Add to Access Token”

✅ 总结

Mapper 类型 适用场景 是否推荐
User Attribute 将用户属性注入 Token ✅ 推荐
Role Name 显示用户角色 ✅ 推荐
Group Membership 显示用户所属组 ✅ 推荐
Hardcoded Claim 固定字段 ✅ 快速调试
Script Mapper 动态生成字段(如权限) ✅ 高级用法
Audience 添加目标受众 ✅ 安全增强

如果你能提供以下信息,我可以为你写出完整的配置指南:

  • Realm 名称
  • Client ID
  • 想要添加的字段名(如 tenant_idorg_code 等)
  • 你是想从 user 用户属性还是客户端属性取值
  • 是否使用 client_credentials 模式

欢迎继续提问,我将为你定制完整的配置方案!


网站公告

今日签到

点亮在社区的每一天
去签到