Keycloak 集成
本指南端到端地把一个 Keycloak Realm 接入网关:用户以自己的身份登录 Keycloak,携带获得的 JWT 调用网关,并按部门或群组落到对应的调用方 API Key 上运行——无需向每个人分发 Key,也无需重复维护目录。它是 JWT 认证(信任与验证)和 JWT Claim 映射(评估语义)两篇的实操配套。
你将搭建:
- 一个 Keycloak Realm,其访问令牌携带网关受众(audience)、
departmentclaim 和groupsclaim。 - 网关侧的两把策略 Key——受限的
financeKey 和不受限的平台 Key。 - 两条 Claim 映射:
platform-admin群组的成员使用平台 Key;department = finance的所有人使用 finance Key;其余请求一律拒绝。
以下步骤在 Keycloak 26(quay.io/keycloak/keycloak:26.3 start-dev)上逐步验证过。其他版本中字段的位置可能略有不同,关键在于配置的取值。
第 1 步:创建 Realm 和 Client
创建一个 Realm(本指南使用 aisix),并在其中为需要请求令牌的应用创建一个 OpenID Connect Client:
| Client 设置 | 取值 |
|---|---|
| Client ID | ai-clients |
| Client authentication | 开启(机密客户端——Client 持有密钥) |
| Direct access grants | 若想按下文用 curl 密码授权测试,则开启 |
| Standard flow | 按你的应用登录形态决定 |
在 Client 的 Credentials 页记下 Client Secret。
第 2 步:塑造访问令牌
默认情况下 Keycloak 的访问令牌既不携带网关的受众,也不携带你的目录属性。给 Client 添加三个 Protocol Mapper(Clients → ai-clients → Client scopes → ai-clients-dedicated → Add mapper → By configuration):
| Mapper 类型 | 配置 |
|---|---|
| Audience | Included Custom Audience:aisix-gateway,加入访问令牌。令牌的 aud 不包含任何已配置受众时网关会拒绝。 |
| User Attribute | User Attribute:department,Token Claim Name:department,claim 类型 String,加入访问令牌。 |
| Group Membership | Token Claim Name:groups,Full group path:关闭,加入访问令牌。 |
Keycloak 24 及之后的版本还有一个 Realm 级开关需要注意:department 这类自定义用户属性若未在 Realm 的 User Profile 中声明,会被静默丢弃。要么声明该属性(Realm settings → User profile → Create attribute),要么在同一页面把 Unmanaged attributes 设为 Enabled。否则你在用户上填写的属性根本不会保存,claim 也永远不会出现在令牌里。
第 3 步:创建群组和用户
创建 platform-admin 群组,然后创建用户:
alice——属性department = finance。bob——platform-admin群组成员。charlie——两者都不占,用来验证默认拒绝路径。
给每个用户设置密码和完整的资料(邮箱、名、姓——或在 Realm 的 User Profile 中放宽这些必填要求)。资料不完整或存在待完成必需操作(Required Actions)的用户 在密码授权登录时会失败,报 Account is not fully set up。
第 4 步:在网关侧信任该 Realm
把 Realm 注册为信任提供方。issuer 必须与令牌的 iss claim 逐字节相同——对名为 aisix 的 Realm 来说就是 <Keycloak 基础 URL>/realms/aisix——JWKS URI 会由此自动发现。
在资源文件中:
oidc_providers:
- name: corp-keycloak
issuer: https://sso.example.com/realms/aisix
audiences: ["aisix-gateway"]
受管部署则在控制台 Trust Providers 中创建同样的提供方,或调用 Admin API——字段完全一致(参见 JWT 认证)。
第 5 步:把部门和群组映射到策略 Key
创建两把策略 Key 和两条映射。群组规则使用更优(更小)的优先级,这样身在 finance 部门的平台管理员仍然落在平台 Key 上:
api_keys:
- display_name: finance-policy-key
key_env: FINANCE_POLICY_KEY
allowed_models: ["finance-model"]
- display_name: admin-policy-key
key_env: ADMIN_POLICY_KEY
allowed_models: ["*"]
claim_mappings:
- name: platform-admins
jwt_provider: corp-keycloak
priority: 50
match:
- claim: groups
op: contains
values: ["platform-admin"]
resolve:
api_key: admin-policy-key
- name: finance-dept
jwt_provider: corp-keycloak
priority: 100
match:
- claim: department
op: exact
values: ["finance"]
resolve:
api_key: finance-policy-key
contains 是针对 Keycloak 数组型 claim 的操作符(这里的 groups,或 Realm 角色对应的 realm_access.roles——点号会深入嵌套对象);exact 适合 department 这类单值属性。评估顺序、并列打破规则,以及与 jwt_subject 直接绑定的交互,见 JWT Claim 映射。