a6-plugin-jwt-auth
概览
jwt-auth 插件使用 JSON Web Token 对请 求进行认证。消费者
会注册 key 和 secret(或用于非对称算法的公钥)。客户端
在请求头、查询参数或 Cookie 中包含已签名 JWT。Apache APISIX
会校验签名和声明,然后携带消费者
身份请求头转发请求。
适用场景
- 基于 Token 的无状态认证
- 非对称密钥校验(RS256、ES256、EdDSA),Apache APISIX只需要公钥
- 基于自定义声明识别消费者
- 与外部 Token 签发方集成,例如自建认证服务、Auth0 等
消费者凭证参考
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
key | string | 是 | — | JWT 载荷中用于匹配消费者的唯一标识符 |
secret | string | 有条件 | — | 用于 HMAC 算法(HS256/HS384/HS512)的共享 Secret,在 etcd 中加密存储 |
public_key | string | 有条件 | — | 用于 RSA/ECDSA/EdDSA 算法的 PEM 公钥 |
algorithm | string | 否 | "HS256" | 签名算法,参见下方支持的算法列表 |
exp | integer | 否 | 86400 | Token 有效期,单位为秒,不是 UNIX 时间戳 |
base64_secret | boolean | 否 | false | 如果 secret 使用 Base64 编码,则设为 true |
lifetime_grace_period | integer | 否 | 0 | 允许的时钟偏差,单位为秒 |
key_claim_name | string | 否 | "key" | 包含消费者 key 的 JWT 声明 |
支持的算法
| 系列 | 算法 |
|---|---|
| HMAC | HS256, HS384, HS512 |
| RSA | RS256, RS384, RS512 |
| RSA-PSS | PS256, PS384, PS512 |
| ECDSA | ES256, ES384, ES512 |
| EdDSA | EdDSA |
路由/服务配置参考
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
header | string | 否 | "authorization" | 从请求头提取 JWT |
query | string | 否 | "jwt" | 从查询参数提取 JWT |
cookie | string | 否 | "jwt" | 从 Cookie 提取 JWT |
hide_credentials | boolean | 否 | false | 转发到上游前移除 JWT |
key_claim_name | string | 否 | "key" | 包含消费者 key 的 JWT 声明,必须与凭证配置匹配 |
anonymous_consumer | string | 否 | — | 用于未认证请求的消费者 |
claims_to_verify | array | 否 | ["exp","nbf"] | 要校验的声明(exp、nbf) |
Token 查找优先级
- 请求头(默认:
authorization):支持Bearer <token>前缀 - 查询参数(默认:
jwt) - Cookie(默认:
jwt)
分步操作:使用 HS256 启用 jwt-auth
1. 创建消费者
a6 consumer create -f - <<'EOF'
{
"username": "alice"
}
EOF
2. 添加 jwt-auth 凭证
curl "$(a6 context current -o json | jq -r .server)/apisix/admin/consumers/alice/credentials" \
-X PUT \
-H "X-API-KEY: $(a6 context current -o json | jq -r .api_key)" \
-d '{
"id": "cred-alice-jwt",
"plugins": {
"jwt-auth": {
"key": "alice-key",
"secret": "alice-secret-minimum-32-chars-long",
"algorithm": "HS256",
"exp": 86400
}
}
}'
3. 创建启用 jwt-auth 的路由
a6 route create -f - <<'EOF'
{
"id": "jwt-protected",
"uri": "/api/*",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
4. 生成 JWT 并测试
创建载荷为 {"key": "alice-key", "exp": <future_timestamp>} 的 JWT
并使用 alice-secret-minimum-32-chars-long 通过 HS256 签名。
curl -i http://127.0.0.1:9080/api/test \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
分步操作:使用 RS256 启用 jwt-auth
1. 生成 RSA 密钥对
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
2. 使用公钥创建凭证
curl "$(a6 context current -o json | jq -r .server)/apisix/admin/consumers/bob/credentials" \
-X PUT \
-H "X-API-KEY: $(a6 context current -o json | jq -r .api_key)" \
-d '{
"id": "cred-bob-jwt",
"plugins": {
"jwt-auth": {
"key": "bob-key",
"algorithm": "RS256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjAN...\n-----END PUBLIC KEY-----"
}
}
}'
在外部使用 private.pem 签发 Token。Apache APISIX只需要公钥。
常见模式
自定义声明名称(使用 iss 代替 key)
# Credential config:
{
"jwt-auth": {
"key": "my-issuer-id",
"secret": "my-secret",
"key_claim_name": "iss"
}
}
# Route config:
{
"jwt-auth": {
"key_claim_name": "iss"
}
}
# JWT payload:
{
"iss": "my-issuer-id",
"exp": 1879318541
}
时钟偏移容忍度
{
"jwt-auth": {
"key": "consumer-key",
"secret": "my-secret",
"lifetime_grace_period": 30
}
}
允许 Token 签发方与 Apache APISIX之间存在 30 秒时钟偏移。
查询参数中的 Token
{
"plugins": {
"jwt-auth": {
"query": "token"
}
}
}
客户端发送:curl "http://127.0.0.1:9080/api/test?token=eyJ..."
使用环境变量管理密钥
{
"jwt-auth": {
"key": "consumer-key",
"secret": "$env://JWT_SECRET"
}
}
使用 HashiCorp Vault 管理密钥
{
"jwt-auth": {
"key": "consumer-key",
"secret": "$secret://vault/jwt/consumer-name/jwt-secret"
}
}
添加到上游的请求头
| 请求头 | 值 |
|---|---|
X-Consumer-Username | 消费者用户名 |
X-Credential-Identifier | 凭证 ID |
X-Consumer-Custom-Id | 消费者的 labels.custom_id(如已设置) |
错误响应
| HTTP 状态码 | 消息 | 原因 |
|---|---|---|
| 401 | "Missing JWT token in request" | 请求头、查询参数或 Cookie 中没有 Token |
| 401 | "JWT token invalid" | Token 格式错误 |
| 401 | "failed to verify jwt" | 签名错误、已过期或声明无效 |
| 401 | "Invalid user key in JWT token" | 未找到消费者 key |
故障排查
| 现象 | 原因 | 修复方式 |
|---|---|---|
401 "failed to verify jwt" | Token 已过期 | 使用未来的 exp 生成新 Token |
401 "failed to verify jwt" | 算法不匹配 | 确保凭证 algorithm 与 Token 匹配 |
401 "Invalid user key" | 声明名称错误 | 在凭证和路由上同时设置 key_claim_name |
| 公钥被拒绝 | PEM 中缺少换行 | 在 header 后、footer 前包含 \n |
| 时钟偏移错误 | 存在时间漂移 | 在凭证上设置 lifetime_grace_period |
配置同步示例
version: "1"
consumers:
- username: alice
routes:
- id: jwt-protected
uri: /api/*
plugins:
jwt-auth: {}
upstream_id: my-upstream
upstreams:
- id: my-upstream
type: roundrobin
nodes:
"backend:8080": 1
注意:消费者凭证(包括 JWT key/secret)必须通过 Admin API 单独管理;
a6 config sync会管理消费者资源,但凭证属于子资源。
本文根据 api7/a6 仓库中的 a6-plugin-jwt-auth/SKILL.md 生成。可在 AI Agent Skills 页面浏览全部 Skill。