JWT Claim 映射
JWT 认证可以通过 jwt_provider 和 jwt_subject 字段,将一个外部身份绑定到一把调用方 API Key。这适用于固定的 Agent 集群,但无法扩展到由企业身份提供商为数百人声明部门、群组或应用的场景。为每个人注册一把 Key 会重复维护 IdP 的目录,而目录中的变更也不会自动传播。
Claim 映射弥补了这一缺口。映射会匹配已验证的 JWT Claim(例如部门名称或群组成员身份),并将请求解析到现有的调用方 API Key。规则放行的所有身份都会继承该 Key 的模型访问权限、工具访问权限和限流;在 AISIX Cloud 中,还会继承其预算。用量事件仍会归因到 Token 中的具体身份。
Claim 只能选择运营者已经创建的 Key。任何 Claim 值都不会成为配置:Token 无法指定上游、扩大模型允许列表或创建预算。AISIX 会拒绝既没有匹配直接绑定、也没有匹配 Claim 映射的 Token。
映射如何求值
对于每个携带 JWT Bearer 的请求,在完成 JWT 认证所述的完整信任提供商验证之后:
- 如果某把调用方 API Key 通过
jwt_subject和jwt_provider直接绑定了 Token 的 Subject,请求会以该 Key 的身份运行。直接绑定对该 Subject 具有最高权威;即使该 Key 已禁用,请求也会被拒绝,映射不会覆盖它。 - 否则,AISIX 会评估
jwt_provider指向已匹配信任提供商的所有已启用映射。priority值越小越先评估,同值时按name排序;第一条所有match条件均成立的映射会选定所用的 Key。 - 如果没有映射匹配,请求会被拒绝并返回
jwt_identity_unmapped,不存在默认放行。
映射的 match 字段是一组必须全部成立的条件:
| 字段 | 说明 |
|---|---|
claim | 非空的 Claim 路径。点号用于遍历嵌套对象(例如 realm_access.roles)。缺失的 Claim 永不匹配。 |
op | 使用 exact 时,Claim 必须是与 values 之一相等的字符串。使用 contains 时,Claim 必须是数组,且其字符串元素中包含 values 之一;非字符串元素会被忽略。类型与操作符不符的 Claim 永不匹配。 |
values | 一个或多个可接受的字符串,任意一个匹配即满足该条件。 |
jwt_provider 指定的信任提供商必须先验证 Token,AISIX 才会考虑任何映射。在 AISIX Cloud 中,映射的 Key 必须持续存在于同一环境中,因此删除被某条映射指向的 Key 会被拒绝——请先改指向或删除该映射。在声明式资源文件中,引用未知的提供商或 Key 会阻止配置加载。
前提条件
开始之前,请准备:
- 按照 JWT 认证配置的 OIDC 信任提供商和模型。
- 一把充当共享策略 Key 的调用方 API Key。配置允许放行的身份应继承的模型访问权限、工具访问权限和限流;在 AISIX Cloud 中,还会应用匹配的预算。
- 选择一种配置路径:
- AISIX Cloud:准备一个环境、已连接的网关,以及具有
writeScope 的管理员 Token,并记录策略 Key 的 ID。 - 开源 AISIX 网关:准备完整的
resources.yaml文件,并能够设置网关进程环境变量。
- AISIX Cloud:准备一个环境、已连接的网关,以及具有
- AISIX Cloud 工作流需要
curl和jq;开源工作流使用 OpenSSL 生成下文所示的策略 Key 值。
检查信任提供商要求
AISIX 会先评估信任提供商要求,再评估 Claim 映射。请删除或更新应由映射作出判断的 bound_claims 条件。在本工作流中,删除 JWT 认证示例中的 department: ai-lab 条件,因为由映射决定放行哪些部门。
保留获准身份能够满足的 required_scopes 要求。示例保留 ai.access,因此映射的 Token 必须携带该 Scope。请按照更新或删除信任提供商应用提供商变更。
配置 Claim 映射
使用与部署方式对应的管理路径配置 Claim 映射。
AISIX Cloud
导出 AISIX Cloud Admin API 连接信息、环境 ID 和策略 Key ID:
# AISIX_CP 包含 /api,末尾不带斜杠。
# 本地 On-Premises 快速入门使用 http://localhost:8080/api。
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
export POLICY_KEY_ID="YOUR_API_KEY_ID"
把 department Claim 等于 finance 的所有身份放行到策略 Key 下:
curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/claim_mappings" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "finance-dept",
"jwt_provider": "corp-keycloak",
"priority": 100,
"match": [
{
"claim": "department",
"op": "exact",
"values": ["finance"]
}
],
"resolve": {
"api_key_id": "'"$POLICY_KEY_ID"'"
}
}' | jq
响应会回显创建的映射。如果环境中的部分网关运行的版本早于 Claim 映射特性,响应还会包含 warnings 数组。这些网关会完全跳过该规则,持续拒绝本应放行的身份,因此请先升级它们再依赖此规则。
映射字段
| 字段 | 说明 |
|---|---|
name | 映射名称,在环境内唯一且创建后不可更改。也是优先级相同时的求值决胜依据。 |
jwt_provider | 此映射适用的 OIDC 提供商名称。映射不会匹配由其他提供商验证的 Token,因此两个提供商无法选择彼此的 Key。 |
priority | 在该提供商的映射中的 非负求值顺序。数值越小越先评估,默认为 0。 |
match | 1 到 16 个必须全部成立的 Claim 条件(见上表)。 |
resolve.api_key_id | 匹配请求所使用的调用方 API Key ID。 |
enabled | 映射是否参与求值。默认为 true;禁用的映射会保留但被跳过。 |
AISIX Cloud Admin API 接受最长 120 个字符的映射名称和提供商名称。一个映射可包含 1 到 16 个条件。每个条件的 Claim 路径最长 256 个字符,可包含 1 到 64 个可接受值,每个值最长 256 个字符。
使用 PATCH .../claim_mappings/{claim_mapping_id} 更新映射。名称不可更改,因此重命名需要删除后重新创建。使用 DELETE 删除映射。变更对新请求即时生效,无需重启网关;仅由已删除或已禁用映射放行的身份,会在网关获取变更后立即停止认证。
Dashboard 中环境的 Claim 映射 页面管理相同的规则,并按求值顺序显示规则列表。
开源 AISIX 网关
此配置扩展了 JWT 认证中的完整资源文件。保留该文件的 _format_version、服务提供方密钥和模型条目。将新的策略 Key 值设置到网关进程环境中:
export FINANCE_POLICY_KEY="$(openssl rand -hex 32)"
使用此条目替换 corp-keycloak,不要添加第二个同名提供商。它保留 ai.access Scope,同时将部门判定移交给映射:
oidc_providers:
- name: corp-keycloak
issuer: https://sso.example.com/realms/agents
audiences: ["aisix-gateway"]
required_scopes: ["ai.access"]
将 finance-policy-key 添加到现有 api_keys 列表。将 finance-dept 添加到 claim_mappings;如果顶层 claim_mappings 集合不存在,只创建一次。保留两个集合中的现有条目,不要重复创建任何一个顶层集合键。
在组装后的 resources.yaml 中,resolve.api_key 按策略 Key 的 display_name 引用它:
api_keys:
- display_name: finance-policy-key
key_env: FINANCE_POLICY_KEY
allowed_models: ["gpt-4o-prod"]
claim_mappings:
- name: finance-dept
jwt_provider: corp-keycloak
priority: 100
match:
- claim: department
op: exact
values: ["finance"]
resolve:
api_key: finance-policy-key
name、jwt_provider、priority、match 和 enabled 字段的求值行为与 AISIX Cloud 中相同。开源 Schema 会验证名称、提供商、条件列表、Claim 路径和值列表均非空,但不应用 AISIX Cloud Admin API 的最大长度或列表大小限制。
文件加载器会在加载时解析引用,并拒绝未知的提供商或 Key 名称、空条件列表,以及 jwt_provider 指向文件中不存在的提供商的映射。拼写错误会导致加载失败,而不是静默地永不匹配。
按照重新加载资源文件验证并应用完整文件。如果 FINANCE_POLICY_KEY 是新增变量,请按照添加新的环境变量使用该变量重新创建网关。
在宿主机上导出变量并发送 SIGHUP,无法将变量添加到已运行的容器中。
若要保留映射配置但禁用它,请设置 enabled: false 并重新加载文件。若要删除映射,请删除对应条目并重新加载。删除策略 Key 前,需要删除或重新指向每个引用它的映射;可以在之前的一次重新加载中应用这些变更,也可以在同一个资源文件更新中完成。文件加载器会拒绝映射引用缺失 Key 的任何配置。
用优先级分层组合映射
规则通过优先级组合。为更精确的规则设置更小的值,使其优先作用于所描述的身份,再由更宽泛的规则处理其余身份。
对于 AISIX Cloud,先导出第二把策略 Key 的 ID,再创建更精确的映射:
export ADMIN_KEY_ID="YOUR_ADMIN_API_KEY_ID"
curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/claim_mappings" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "platform-admins",
"jwt_provider": "corp-keycloak",
"priority": 50,
"match": [
{
"claim": "groups",
"op": "contains",
"values": ["platform-admin"]
}
],
"resolve": {
"api_key_id": "'"$ADMIN_KEY_ID"'"
}
}' | jq
同时携带 department: finance 和 platform-admin 群组的 Token 会通过优先级为 50 的 platform-admins 解析,而不是优先级为 100 的 finance-dept。需要不同有效访问控制的身份应解析到不同的策略 Key;多个映射也可以在需要授予相同访问权限时解析到同一把 Key。
对于开源网关,Keycloak 集成提供了体现相同优先级关系的完整双规则资源文件。
验证 Claim 映射
获取一个符合以下条件的 JWT:其已验证的 Claim 应匹配此映射,且其 Subject 未通过 jwt_subject 和 jwt_provider 直接绑定。然后请求只有预期策略 Key 才允许的模型,或者确认 AISIX Cloud 日志或已配置的导出器中出现了预期的 jwt_claim_mapping。这样可以区分映射命中与通过其他 Key 获得访问权限的情况。
还需要测试适用于规则的默认拒绝和优先级路径:
- 发送一个既不匹配直接绑定、也不匹配任何映射的有效 JWT。在 OpenAI 风格的代理路由上,网关应返回
401,且error.code为jwt_identity_unmapped。 - 如果映射重叠,请使用没有直接绑定的 Subject,并发送同时匹配两条映射的 JWT。请求只有高优先级映射所选策略 Key 才允许的模型,或者确认预期的
jwt_claim_mapping归因。这可以验证较小的priority值已生效。
有关涵盖两种配置路径的可复现 Keycloak 设置和验证矩阵,请参阅 Keycloak 集成。
按身份归因用量
经映射放行的请求,其用量事件包含三个归因字段。已配置的可观测性导出器会收到相同字段:
| 字段 | 说明 |
|---|---|
jwt_subject | Token 身份 Claim 的值;即使多个身份共享策略 Key,也能识别请求由谁发起。 |
jwt_provider | 验证该 Token 的信任提供商。 |
jwt_claim_mapping | 放行该请求的映射。通过 jwt_subject 和 jwt_provider 直接绑定的身份,此字段为空。 |
在 AISIX Cloud 中,这些 字段也会显示在环境的 Logs 中,并包含在 CSV 导出中。Logs 页面支持按 JWT Subject 过滤,用量事件 API 上的 jwt_subject 和 jwt_claim_mapping 查询参数可收窄程序化读取结果。
当身份 Claim 包含姓名或电子邮件地址时,Subject 属于个人数据。将导出器与 Claim 映射一起启用之前,请检查导出器会把用量数据发送到何处。
拒绝行为
映射认证扩展了 JWT 拒绝原因表。当身份无法安全解析时,AISIX 会在已验证 Token 到达模型提供商、MCP 服务器或向量存储之前将其拒绝。
以下每种失败都会返回 HTTP 401。OpenAI 风格的路由在 error.code 中返回 jwt_identity_unmapped,而 aisix_auth_decisions_total 的 reason 标签会标识面向运营者的具体原因:
reason | 含义 |
|---|---|
jwt_identity_unmapped | 已验证的身份没有直接 Key 绑定,并且其信任提供商没有任何已启用映射能够匹配全部 Claim 条件。 |
claim_mapping_target_missing | 某个映射已匹配,但其目标调用方 API Key 不在网关当前有效配置中。AISIX Cloud 和资源文件验证通常会阻止这种状态。如果仍然出现,请检查配置传播和网关的有效资源。 |
jwt_binding_ambiguous | 多把调用方 API Key 具有相同的 jwt_provider 和 jwt_subject 绑定,因此网关会以失败关闭方式拒绝,而不是继续评估映射。正常的配置验证 会阻止这种状态。 |
后续步骤
- Keycloak 集成:从 Keycloak Realm 到映射且归因的请求,一份经过完整验证的端到端指南。
- JWT 认证:所有映射所基于的信任提供商验证。
- 调用方 API Key:策略 Key 承载的模型访问权限、工具访问权限、限流,以及在 AISIX Cloud 中的预算。
- API Key 与模型限流:为共享 Key 的流量设限。