Kong API gateway 如何生成、验证 token 并转发至后端?
接入第三方 Identity provider(IdP)后,通常由 IdP 签发 access token。Kong 验证 token、检查访问权限,再将通过验证的请求转发到后端。如果后端需要原始 token,可以通过 Authorization: Bearer <access_token> 接收。
服务间调用和 UI 调用都可以采用这一流程,区别主要在于 token 的获取方式,以及它代表应用身份还是用户身份。Kong 官方 OpenID Connect 插件支持第三方 IdP,但标注为 Enterprise only,配置前需确认当前部署是否支持。Kong OpenID Connect 文档
1. Token 由谁生成,Kong 如何验证?
在这种架构中,调用方已经从 IdP 获取 token,Kong 无须重新签发:
调用方向 IdP 获取 access token
↓
调用方携带 access token 请求 Kong
↓
Kong 验证 token,并检查目标 API 所需权限
↓
验证通过后,Kong 将请求和 token 转发给后端
验证方式取决于 IdP 签发的 token 类型:
| Token 类型 | Kong 的验证方式 |
|---|---|
| 签名 JWT access token | 使用可信 IdP 发布的公钥验证签名,并检查相关 claims |
| Opaque token,即无法直接解析内容的不透明 token | 调用 IdP 的 introspection endpoint 查询 token 状态,再检查返回的权限信息 |
在 OpenID Connect 插件中,验证 JWT access token 使用 auth_methods: ["bearer"],introspection 使用 auth_methods: ["introspection"]。Opaque token 同样通过 Bearer 请求头发送,但无法通过 JWT 本地验签来验证。Kong 认证流程说明
2. 服务间调用:服务取 token,Kong 验证后转发
服务 A 使用自己的 client_id、client_secret 和 scope 获取 token,通常采用 OAuth 2.0 的 Client Credentials Grant。此时,token 代表服务 A 的应用身份。
假设 IdP 支持 client_secret_basic,可以通过以下请求获取 token:
curl --fail-with-body \
--request POST 'https://idp.example.com/oauth2/token' \
--user "${CLIENT_ID}:${CLIENT_SECRET}" \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=orders.read'
将响应中的 access_token 保存到 ACCESS_TOKEN 后,请求 Kong:
curl --fail-with-body \
'https://api.example.com/api/orders' \
--header "Authorization: Bearer ${ACCESS_TOKEN}"
Token endpoint 和客户端认证方式以 IdP 配置为准。scope 是申请的权限,实际授予哪些权限,还取决于 IdP 中的客户端注册配置。RFC 6749:Client Credentials Grant
Kong 收到请求后,会检查 token 是否可信、是否过期、是否适用于目标 API,以及是否具备 orders.read 等所需权限。检查通过后才将请求转发到后端。
获取 token 和验证 token 使用不同的配置:
- 服务 A 向 IdP 获取 token 时,使用
grant_type=client_credentials。 - Kong 接收已签发的 JWT access token 时,使用
auth_methods: ["bearer"]。
在 Kong 上启用 client_credentials 认证流程,会让 Kong 参与向 IdP 换取 token。服务已经自行获取 token 时,无须增加这一步。Kong Client Credentials 配置说明
3. UI 调用:用户登录后携带 access token 请求 API
浏览器 UI 通常采用 Authorization Code Flow with PKCE:
- UI 将用户引导至 IdP 登录。
- 用户完成认证后,UI 获得授权码,再通过 PKCE 换取 token。
- UI 使用 access token 请求 Kong。
- Kong 完成验证和权限检查后,将请求转发到后端。
浏览器应用无法对 client_secret 保密,因此不要将它放进前端代码。OAuth 安全最佳实践要求公共客户端在授权码流程中使用 PKCE。RFC 9700
UI 拿到 access token 后,请求方式与服务间调用一致:
const response = await fetch("https://api.example.com/api/orders", {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const orders = await response.json();
调用 API 应使用 access token。ID token 用于客户端确认用户的登录身份,不应直接作为 API 访问凭证。
如果希望 Kong 接管浏览器的登录重定向和会话管理,可以另行配置 OpenID Connect 的授权码与 session 流程。这与 UI 已经持有 token 再调用 API 是两种不同的接入方式。
4. Kong 配置示例:验证 JWT 并转发原始 token
使用下面的声明式配置,需要满足这些条件:
- 当前 Kong 支持官方
openid-connect插件。 - IdP 提供 OIDC Discovery 和用于验签的 JWKS。
- access token 的
aud包含orders-api,scope包含orders.read。 - Kong 能访问 IdP 和后端服务。
域名、audience 和 scope 均为占位值,需替换为实际配置。
_format_version: "3.0"
services:
- name: orders-service
url: https://orders.internal
routes:
- name: orders-route
paths:
- /api
strip_path: true
plugins:
- name: openid-connect
config:
issuer: https://idp.example.com/.well-known/openid-configuration
auth_methods:
- bearer
bearer_token_param_type:
- header
verify_signature: true
verify_claims: true
audience_required:
- orders-api
scopes_claim:
- scope
scopes_required:
- orders.read
upstream_access_token_header: "authorization:bearer"
按此路由配置,/api/orders 请求会转发到 https://orders.internal/orders。认证插件决定是否放行,Service 和 Route 决定转发目标。
audience_required 限制 token 可访问的 API,scopes_required 检查已授予的权限。如果 IdP 将权限放在 scp 或其他 claim 中,需相应调整 scopes_claim。这些字段是否受支持,应核对所用版本的配置参考。OpenID Connect 配置参考
upstream_access_token_header: "authorization:bearer" 表示向后端发送:
Authorization: Bearer <access_token>
这也是该插件默认的 access token 转发方式。还需检查其他插件是否删除或覆盖了这一请求头。Kong 上游请求头说明
5. 如果 IdP 返回 opaque token
保留前面的 Service 和 Route,将认证插件改为使用 introspection。假设 IdP 支持 HTTP Basic 客户端认证,配置如下:
plugins:
- name: openid-connect
config:
issuer: https://idp.example.com/.well-known/openid-configuration
auth_methods:
- introspection
bearer_token_param_type:
- header
introspection_endpoint: https://idp.example.com/oauth2/introspect
introspection_endpoint_auth_method: client_secret_basic
client_id:
- kong-resource-server
client_secret:
- REPLACE_WITH_INTROSPECTION_CLIENT_SECRET
introspection_check_active: true
audience_required:
- orders-api
scopes_claim:
- scope
scopes_required:
- orders.read
upstream_access_token_header: "authorization:bearer"
这里的 client_id 和 client_secret 是 Kong 调用 introspection endpoint 的凭据,需要在 IdP 中获得相应权限。它们可以与服务 A 获取 token 时使用的凭据不同。生产环境应通过部署环境支持的密钥管理机制注入 secret。Kong Introspection 配置示例
Kong 应检查 introspection 响应中的 active,并根据返回的 audience、scope 等信息执行授权。如果 IdP 未返回所需字段,需要先协调 IdP 的返回内容与网关的校验策略。RFC 7662
6. 接入时容易遗漏的事项
基础 JWT 插件与 OpenID Connect 插件能力不同
Kong 的基础 jwt 插件根据 Consumer 关联的 JWT credential 选择验签密钥,也可以配置检查 exp、nbf。接入第三方 IdP 时,需要自行维护密钥和凭据映射,不能假定该插件会自动完成 OIDC Discovery、JWKS 密钥更新或 scope 授权。Kong JWT 插件文档
如果当前部署无法使用官方 OpenID Connect 插件,应选择能完成所需验证的其他集成方案,并明确由哪一层负责 audience、scope 校验和密钥轮换。
Token 有效还需满足业务权限
网关可以检查 API 级别的 scope,后端仍需判断用户是否有权访问某条订单等具体资源。服务身份和用户身份也应分别处理,不能仅凭 token 中存在 sub 就认定它代表终端用户。
后端接受原始 token 的 issuer、audience 和权限范围时,才能继续使用该 token。如果下游需要不同 audience 的 token,则需设计单独的 token 获取或 token exchange 流程。
撤销、跨域和后端入口的检查
JWT 本地验签通常无法立即感知 IdP 侧的 token 撤销。Introspection 可以查询状态,但缓存会影响撤销的生效时间,需按业务要求配置。RFC 7662 缓存注意事项
浏览器跨域调用时,需要允许 Authorization 请求头,并正确处理 OPTIONS 预检。整个链路应使用 HTTPS,避免在 URL 和日志中记录 token。如果后端依赖 Kong 提供的身份信息,应限制后端入口,防止客户端绕过网关直接访问。
备注:内容仅供参考。
