Skip to main content
Version: Next

jwt-auth

描述#

jwt-auth 插件支持使用 JSON Web Token (JWT) 作为客户端在访问上游资源之前进行身份验证的机制。

启用后,该插件会公开一个端点,供 消费者 创建 JWT 凭据。该过程会生成一个令牌,客户端请求应携带该令牌以向 APISIX 标识自己。该令牌可以包含在请求 URL 查询字符串、请求标头或 cookie 中。然后,APISIX 将验证该令牌以确定是否应允许或拒绝请求访问上游资源。

当消费者成功通过身份验证后,APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 X-Consumer-UsernameX-Credential-Indentifier 和其他消费者自定义标头(如已配置)。上游服务将能够区分消费者并根据需要实施其他逻辑。如果任何一个值不可用,则不会添加相应的标题。

属性#

Consumer/Credential 端:

名称类型必选项默认值有效值描述
keystring消费者的唯一密钥。
secretstring当使用对称算法时,用于对 JWT 进行签名和验证的共享密钥。使用 HS256HS512 作为算法时必填。如果未指定,后台将会自动生成。该字段支持使用 APISIX Secret 资源,将值保存在 Secret Manager 中。
public_keystringRSA 或 ECDSA 公钥, algorithm 属性选择 RS256ES256 算法时必选。该字段支持使用 APISIX Secret 资源,将值保存在 Secret Manager 中。
algorithmstring"HS256"["HS256","HS512","RS256","ES256"]加密算法。
expinteger86400[1,...]token 的超时时间。
base64_secretbooleanfalse当设置为 true 时,密钥为 base64 编码。
lifetime_grace_periodinteger0[0,...]宽限期(以秒为单位)。用于解决生成 JWT 的服务器与验证 JWT 的服务器之间的时钟偏差。
key_claim_namestringkeyJWT payload 中的声明用于标识相关的秘密,例如 iss

注意:schema 中还定义了 encrypt_fields = {"secret"},这意味着该字段将会被加密存储在 etcd 中。具体参考 加密存储字段

Route 端:

名称类型必选项默认值描述
headerstringauthorization设置我们从哪个 header 获取 token。
querystringjwt设置我们从哪个 query string 获取 token,优先级低于 header。
cookiestringjwt设置我们从哪个 cookie 获取 token,优先级低于 query。
hide_credentialsbooleanfalse如果为 true,则不要将 header、query 或带有 JWT 的 cookie 传递给上游服务。
key_claim_namestringkey包含用户密钥(对应消费者的密钥属性)的 JWT 声明的名称。
anonymous_consumerstringfalse匿名消费者名称。如果已配置,则允许匿名用户绕过身份验证。
store_in_ctxbooleanfalse设置为 true 将会将 JWT 负载存储在请求上下文 (ctx.jwt_auth_payload) 中。这允许在同一请求上随后运行的低优先级插件检索和使用 JWT 令牌。

您可以使用 HashiCorp Vault 实施 jwt-auth,以从其加密的 KV 引擎 使用 APISIX Secret 资源。

示例#

以下示例演示了如何在不同场景中使用 jwt-auth 插件。

note

您可以这样从 config.yaml 中获取 admin_key 并存入环境变量:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

使用 JWT 进行消费者身份验证#

以下示例演示了如何使用 JWT 进行消费者密钥身份验证。

创建消费者 jack

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'

为消费者创建 jwt-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret-that-is-very-long"
}
}
}'

使用 jwt-auth 插件创建路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/headers",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

要为 jack 颁发 JWT,您可以使用 JWT.io 的 JWT 编码器 或其他实用程序。如果您使用 JWT.io 的 JWT 编码器,请执行以下操作:

  • 填写 HS256 作为算法。

  • Valid secret 部分中的密钥更新为 jack-hs256-secret-that-is-very-long

  • 使用消费者密钥 jack-key 更新有效 payload;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jack-key",
    "nbf": 1729132271
    }

将生成的 JWT 保存到变量中:

export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU

使用 Authorization 标头中的 JWT 向路由发送请求:

curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"

您应该收到类似于以下内容的 HTTP/1.1 200 OK 响应:

{
"headers": {
"Accept": "*/*",
"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-jwt-auth",
"X-Forwarded-Host": "127.0.0.1"
}
}

使用无效的令牌发送请求以验证:

curl -i "http://127.0.0.1:9080/headers" -H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjU_random_random"

您应该收到类似于以下内容的 HTTP/1.1 401 Unauthorized 响应:

{"message":"failed to verify jwt"}

在请求标头、查询字符串或 Cookie 中携带 JWT#

以下示例演示如何在指定的标头、查询字符串和 Cookie 中接受 JWT。

创建一个消费者 jack

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'

为消费者创建 jwt-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret-that-is-very-long"
}
}
}'

创建一个带有 jwt-auth 插件的路由,并指定请求可以在标头、查询或 cookie 中携带令牌:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {
"header": "jwt-auth-header",
"query": "jwt-query",
"cookie": "jwt-cookie"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

要为 jack 颁发 JWT,您可以使用 JWT.io 的 JWT 编码器 或其他实用程序。如果您使用 JWT.io 的 JWT 编码器,请执行以下操作:

  • 填写 HS256 作为算法。

  • Valid secret 部分中的密钥更新为 jack-hs256-secret-that-is-very-long

  • 使用消费者密钥 jack-key 更新有效 payload;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jack-key",
    "nbf": 1729132271
    }

将生成的 JWT 保存到变量中:

export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU

使用标头中的 JWT 进行验证#

发送标头中包含 JWT 的请求:

curl -i "http://127.0.0.1:9080/get" -H "jwt-auth-header: ${jwt_token}"

您应该收到类似于以下内容的 HTTP/1.1 200 OK 响应:

{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"Jwt-Auth-Header": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU",
...
},
...
}

在查询字符串中使用 JWT 进行验证#

在查询字符串中使用 JWT 发送请求:

curl -i "http://127.0.0.1:9080/get?jwt-query=${jwt_token}"

您应该收到类似于以下内容的 HTTP/1.1 200 OK 响应:

{
"args": {
"jwt-query": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU"
},
"headers": {
"Accept": "*/*",
...
},
"origin": "127.0.0.1, 183.17.233.107",
"url": "http://127.0.0.1/get?jwt-query=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ"
}

使用 Cookie 中的 JWT 进行验证#

使用 cookie 中的 JWT 发送请求:

curl -i "http://127.0.0.1:9080/get" --cookie jwt-cookie=${jwt_token}

您应该收到类似于以下内容的 HTTP/1.1 200 OK 响应:

{
"args": {},
"headers": {
"Accept": "*/*",
"Cookie": "jwt-cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU",
...
},
...
}

在环境变量中管理密钥#

以下示例演示了如何将 jwt-auth 消费者密钥保存到环境变量并在配置中引用它。

APISIX 支持引用通过 NGINX env 指令 配置的系统和用户环境变量。

将密钥保存到环境变量中:

export JACK_JWT_SECRET=jack-hs256-secret-that-is-very-long
tip

如果您在 Docker 中运行 APISIX,需要在启动容器时使用 -e flag 设置环境变量。

创建一个消费者 jack

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'

为消费者创建 jwt-auth 凭证并引用环境变量:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "$env://JACK_JWT_SECRET"
}
}
}'

创建启用 jwt-auth 的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

要为 jack 颁发 JWT,您可以使用 JWT.io 的 JWT 编码器 或其他实用程序。如果您使用 JWT.io 的 JWT 编码器,请执行以下操作:

  • 填写 HS256 作为算法。

  • Valid secret 部分中的密钥更新为 jack-hs256-secret-that-is-very-long

  • 使用消费者密钥 jack-key 更新有效 payload;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jack-key",
    "nbf": 1729132271
    }

将生成的 JWT 保存到变量中:

export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU

发送标头中包含 JWT 的请求:

curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"

您应该会收到 HTTP/1.1 200 OK 响应。

在 Secret Manager 中管理 Secret#

以下示例演示了如何在 HashiCorp Vault 中管理 jwt-auth 消费者密钥,并在插件配置中引用它。

在 Docker 中启动 Vault 开发服务器:

docker run -d \
--name vault \
-p 8200:8200 \
--cap-add IPC_LOCK \
-e VAULT_DEV_ROOT_TOKEN_ID=root \
-e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
vault:1.9.0 \
vault server -dev

APISIX 目前支持 Vault KV 引擎版本 1。请在 Vault 中启用它:

docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv"

您应该会看到类似以下内容的响应:

Success! Enabled the kv secrets engine at: kv/

创建一个 Secret,并配置 Vault 地址和其他连接信息。根据情况相应地更新 Vault 地址:

curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "https://127.0.0.1:8200",
"prefix": "kv/apisix",
"token": "root"
}'

创建消费者 jack

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack"
}'

为消费者创建 jwt-auth 凭证并引用 Secret:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jwt-vault-key",
"secret": "$secret://vault/jwt/jack/jwt-secret"
}
}
}'

创建启用 jwt-auth 的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

在 Vault 中将 jwt-auth 键值设置为 vault-hs256-secret-that-is-very-long

docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack jwt-secret=vault-hs256-secret-that-is-very-long"

您应该会看到类似以下内容的响应:

Success! Data written to: kv/apisix/jack

要为 jack 颁发 JWT,您可以使用 JWT.io 的 JWT 编码器 或其他实用程序。如果您使用 JWT.io 的 JWT 编码器,请执行以下操作:

  • 填写 HS256 作为算法。

  • Valid secret 部分中的密钥更新为 vault-hs256-secret-that-is-very-long

  • 使用消费者密钥 jwt-vault-key 更新有效 payload;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jwt-vault-key",
    "nbf": 1729132271
    }

复制生成的 JWT 并保存到变量:

export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.i2pLj7QcQvnlSjB7iV5V522tIV43boQRtee7L0rwlkQ

发送带有令牌作为标头的请求:

curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"

您应该会收到 HTTP/1.1 200 OK 响应。

使用 RS256 算法签名 JWT#

以下示例演示了如何在实现 JWT 消费者身份验证时使用非对称算法(例如 RS256)对 JWT 进行签名和验证。您将使用 openssl 生成 RSA 密钥对,并使用 JWT.io 生成 JWT,以便更好地理解 JWT 的组成。

生成一个 2048 位 RSA 私钥,并提取相应的 PEM 格式公钥:

openssl genrsa -out jwt-rsa256-private.pem 2048
openssl rsa -in jwt-rsa256-private.pem -pubout -out jwt-rsa256-public.pem

您应该看到在当前工作目录中生成的 jwt-rsa256-private.pemjwt-rsa256-public.pem

访问 JWT.io 的 JWT 编码器 并执行以下操作:

  • 填写 RS256 作为算法。

  • 将私钥内容复制并粘贴到 SIGN JWT: PRIVATE KEY 部分。

  • 使用消费者密钥 jack-key 更新有效负载;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jack-key",
    "nbf": 1729132271
    }

复制生成的 JWT 并保存到变量:

export jwt_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.K-I13em84kAcyH1jfIJl7ls_4jlwg1GzEzo5_xrDu-3wt3Xa3irS6naUsWpxX-a-hmcZZxRa9zqunqQjUP4kvn5e3xg2f_KyCR-_ZbwqYEPk3bXeFV1l4iypv6z5L7W1Niharun-dpMU03b1Tz64vhFx6UwxNL5UIZ7bunDAo_BXZ7Xe8rFhNHvIHyBFsDEXIBgx8lNYMq8QJk3iKxZhZZ5Om7lgYjOOKRgew4WkhBAY0v1AkO77nTlvSK0OEeeiwhkROyntggyx-S-U222ykMQ6mBLxkP4Cq5qHwXD8AUcLk5mhEij-3QhboYnt7yhKeZ3wDSpcjDvvL2aasC25ng

创建一个消费者 jack

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'

为消费者创建 jwt-auth 凭证并配置 RSA 密钥:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"algorithm": "RS256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoTxe7ZPycrEP0SK4OBA2\n0OUQsDN9gSFSHVvx/t++nZNrFxzZnV6q6/TRsihNXUIgwaOu5icFlIcxPL9Mf9UJ\na5/XCQExp1TxpuSmjkhIFAJ/x5zXrC8SGTztP3SjkhYnQO9PKVXI6ljwgakVCfpl\numuTYqI+ev7e45NdK8gJoJxPp8bPMdf8/nHfLXZuqhO/btrDg1x+j7frDNrEw+6B\nCK2SsuypmYN+LwHfaH4Of7MQFk3LNIxyBz0mdbsKJBzp360rbWnQeauWtDymZxLT\nATRNBVyl3nCNsURRTkc7eyknLaDt2N5xTIoUGHTUFYSdE68QWmukYMVGcEHEEPkp\naQIDAQAB\n-----END PUBLIC KEY-----"
}
}
}'
tip

您应该在起始行之后和结束行之前添加换行符,例如 -----BEGIN PUBLIC KEY-----\n......\n-----END PUBLIC KEY-----

密钥内容可以直接连接。

使用 jwt-auth 插件创建路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/headers",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

使用 Authorization 标头中的 JWT 向路由发送请求:

curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"

您应该会收到 HTTP/1.1 200 OK 响应。

将消费者自定义 ID 添加到标头#

以下示例演示了如何在 Consumer-Custom-Id 标头中将消费者自定义 ID 附加到已验证的请求,该 ID 可用于根据需要实现其他逻辑。

创建一个带有自定义 ID 标签的消费者 jack

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack",
"labels": {
"custom_id": "495aec6a"
}
}'

为消费者创建 jwt-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret-that-is-very-long"
}
}
}'

使用 jwt-auth 创建路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-auth-route",
"uri": "/anything",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

要为 jack 颁发 JWT,您可以使用 JWT.io 的 JWT 编码器 或其他实用程序。如果您使用 JWT.io 的 JWT 编码器,请执行以下操作:

  • 填写 HS256 作为算法。

  • Valid secret 部分中的密钥更新为 jack-hs256-secret-that-is-very-long

  • 使用消费者密钥 jack-key 更新有效 payload;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jack-key",
    "nbf": 1729132271
    }

复制生成的 JWT 并保存到变量:

export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU

为了验证,使用 Authorization 标头中的 JWT 向路由发送请求:

curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"

您应该会看到类似以下内容的 HTTP/1.1 200 OK 响应:

{
"headers": {
"Accept": "*/*",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-6873b19d-329331db76e5e7194c942b47",
"X-Consumer-Custom-Id": "495aec6a",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-jwt-auth",
"X-Forwarded-Host": "127.0.0.1"
}
}

匿名消费者的速率限制#

以下示例演示了如何为普通消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者无需身份验证,且配额较少。

创建一个普通消费者 jack,并配置 limit-count 插件,允许在 30 秒内使用 3 个配额:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'

为消费者 jack 创建 jwt-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret-that-is-very-long"
}
}
}'

创建匿名用户 anonymous,并配置 limit-count 插件,以允许 30 秒内配额为 1:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'

创建一个路由并配置 jwt-auth 插件以接受匿名消费者 anonymous 绕过身份验证:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-auth-route",
"uri": "/anything",
"plugins": {
"jwt-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

要为 jack 颁发 JWT,您可以使用 JWT.io 的 JWT 编码器 或其他实用程序。如果您使用 JWT.io 的 JWT 编码器,请执行以下操作:

  • 填写 HS256 作为算法。

  • Valid secret 部分中的密钥更新为 jack-hs256-secret-that-is-very-long

  • 使用消费者密钥 jack-key 更新有效 payload;并添加 expnbf UNIX 时间戳。

    您的 payload 应类似于以下内容:

    {
    "key": "jack-key",
    "nbf": 1729132271
    }

将生成的 JWT 复制到 Encoded 部分并保存到变量中:

export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU

为了验证速率限制,请使用 jack 的 JWT 连续发送五个请求:

resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H "Authorization: ${jwt_token}" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429

您应该看到以下响应,显示在 5 个请求中,3 个请求成功(状态代码 200),而其他请求被拒绝(状态代码 429)。

200:    3, 429:    2

发送五个匿名请求:

resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429

您应该看到以下响应,表明只有一个请求成功:

200:    1, 429:    4