keycloak~通过用户ID直接置换token

Keycloak Token Exchange + Impersonation(运维配置)

门户 GET /kc/exchange-token 新流程:

  1. 用请求头里的 WSO2 应用 access_token 调 mcp-admin:POST /internal/wso2/token/authz-user → 得到 kcUserId(来自 idn_oauth2_access_token.AUTHZ_USER
  2. 用 Keycloak 客户端 wso2client_credentials 拿到服务账号 token
  3. 再用 Token Exchange,带 requested_subject={kcUserId},签发该用户的 KC access_token

因此 不要求 WSO2 应用 token 带 openid scope,但要求 Keycloak 客户端具备 Service Account + Token Exchange(用户模拟) 权限。

以下以客户端 ID wso2、Realm fabao 为例(与 application-*.ymlkeycloak.client-id 一致)。


一、客户端基础开关

登录 Keycloak Admin Console → Realm fabaoClientswso2

建议值
Client authentication On
Authentication flow / Standard flow 按现有对接保留
Service accounts roles On(必须,用于 client_credentials)
Direct access grants 可不依赖
Valid redirect URIs / Web origins 按现有配置

保存后,在 Credentials 页确认 client-secret 与各环境 KEYCLOAK_WSO2_CLIENT_SECRET / yml 一致。


二、开通 Token Exchange(推荐:Permissions 模式,适用于多数现网 KC)

不同 Keycloak 大版本菜单位置略有差异,目标是:允许客户端 wso2 用自己的服务账号 token,对任意(或指定)用户做 requested_subject 交换。

2.1 开启客户端 Permissions

  1. Clients → wso2Permissions(或 Authorization)
  2. Permissions enabled 设为 On
  3. 等待出现权限列表(含 token-exchange、可能还有 impersonate 等)

2.2 配置 token-exchange 权限

  1. 打开权限 token-exchange
  2. Decision Strategy:Affirmative(或按现网规范)
  3. 关联一条 Client Policy
    • 新建 Policy → 类型 Client
    • Clients:勾选 wso2
    • Logic:Positive
  4. 将该 Policy 绑到 token-exchange Permission 并 Save

image

2.3 配置用户 Impersonation(requested_subject 必需)

requested_subject 属于「用 A 的 token 换 B 用户的 token」,除 token-exchange 外通常还要 impersonation

方式 A(常用,粒度到用户权限):

  1. Realm → Users → 任意用户 → Permissions(需先在 Realm Settings 开启 Users permissions;部分版本在 Realm settings → User registration / Permissions
  2. 或:Realm → Permissions / Authorization 中找到用户 impersonation 相关权限
  3. 更稳妥的现网做法见 方式 B

方式 B(服务账号角色,配置简单,权限较大):

  1. Clients → wso2Service account roles
  2. Client roles 来源选 realm-management
  3. 分配角色:
    • impersonation(必须)
    • 若列表里还有与 token-exchange 相关的角色可一并勾选(视版本而定)
  4. Save

方式 B 权限面更大(可模拟 realm 内用户),仅限受信的内部客户端 wso2,密钥严格保管。

image

2.4(可选)Audience / Client scope

若换出的用户 token 需要特定 audience 或 scope(门户后续 jwt-bearer 进 APIM 依赖 claim):

  • Clients → wso2Client scopes:保证默认 scope 含业务所需(至少 openid,与 yml keycloak.scope 一致)
  • Token Exchange 请求里门户已传 scope=openid(可配置)

三、自检(运维验证)

{KC_TOKEN_URI}{CLIENT_ID}{CLIENT_SECRET}{KC_USER_ID} 换成实际值。

3.1 client_credentials

curl -s -X POST '{KC_TOKEN_URI}' \
  -u '{CLIENT_ID}:{CLIENT_SECRET}' \
  -d 'grant_type=client_credentials' \
  -d 'scope=openid'

应返回 access_token。记下为 ACTOR_TOKEN

3.2 token-exchange + requested_subject

curl -s -X POST '{KC_TOKEN_URI}' \
  -u '{CLIENT_ID}:{CLIENT_SECRET}' \
  -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
  -d 'subject_token={ACTOR_TOKEN}' \
  -d 'subject_token_type=urn:ietf:params:oauth:token-type:access_token' \
  -d 'requested_token_type=urn:ietf:params:oauth:token-type:access_token' \
  -d 'requested_subject={KC_USER_ID}' \
  -d 'scope=openid'

成功:返回用户 access_token;解码 JWT 后 sub(或等价用户标识)应为该用户。

常见失败:

现象 处理
Client not allowed to exchange / not allowed to impersonate 补全 2.2 / 2.3
Client not enabled for service accounts 打开 Service accounts roles
Invalid user credentials / user not found 确认 AUTHZ_USER / kcUserId 是 Realm 内真实用户 ID(UUID)或用户名,与 Keycloak 用户匹配
unauthorized_client client-secret 或 client-id 错误
posted @ 2026-09-17 13:34  张占岭  阅读(8)  评论(0)    收藏  举报