使用 Auth0 为 M2M 请求授权
Auth0 是一个可以向应用颁发访问 Token 的云身份平台。后台服务、计划任务、命令行工具和自动化程序可以使用这些 Token 调用 API,而无需最终用户登录。
OAuth 2.0 客户端凭证流程专为此类机器到机器(M2M)通信而设计。Apache APISIX 可以在代理请求前验证每个 Token 的签名、颁发者、受众和所授予的权限,从而保护目标 API。
本指南介绍如何为 APISIX 配置 Auth0 自定义 API 和 M2M 应用。该应用获得读取受保护消息的权限,并使用客户端凭证请求访问 Token。APISIX 使用 Auth0 的 JSON Web Key Set(JWKS)在本地验证 Token,并在将请求转发到示例上游之前移除身份认证数据。
前置条件
配置 Auth0
注册自定义 API 以定义 Token 受众和权限,然后配置可请求这些权限的 M2M 应用。
创建自定义 API
登录 Auth0 控制台并创建 API:
- 选择 Applications → APIs → Create API。
- 输入
APISIX Protected API作为 API 名称。 - 输入
https://apisix.example.com作为标识符。 - 保持 Auth0 作为 JWT 配置文件,并保持 RS256 作为签名算法。
- 选择 Create。
API 标识符会成为为该 API 颁发的访问 Token 的受众。它用于标识 API,但不必解析为网络端点。
添加 API 权限
在 API 的 Permissions 标签页中,创建 APISIX 路由所需的权限:
- 输入
read:messages作为权限。 - 输入
Read protected messages作为说明。 - 选择 Add。
配置 M2M 应用
注册自定义 API 时,Auth0 会创建一个测试 M2M 应用。为本指南配置该应用:
- 选择 Applications → Applications。
- 选择 APISIX Protected API (Test Application)。
- 在 Settings 标签页上,将应用重命名为
APISIX M2M Client,然后选择 Save Changes。 - 选择 API Access。
- 在 APISIX Protected API 行中选择 Edit。
- 选择 Client Access,选中
read:messages,然后选择 Save。

在生产环境中,请为每个调用服务分别注册 M2M 应用,并且只授予该服务所需的权限。
保存 OAuth 配置
在 M2M 应用的 Settings 标签页上记录 Domain、Client ID 和 Client Secret。将它们与 API 标识符一起保存到环境变量中,并替换示例值:
export AUTH0_DOMAIN=your-tenant.us.auth0.com
export AUTH0_M2M_CLIENT_ID=replace-with-your-m2m-client-id
export AUTH0_M2M_CLIENT_SECRET=replace-with-your-m2m-client-secret
export AUTH0_API_AUDIENCE=https://apisix.example.com
export AUTH0_DISCOVERY="https://${AUTH0_DOMAIN}/.well-known/openid-configuration"
请妥善保管客户端密钥。将生产凭证存储在 Secret 管理器中,并按照组织的凭证轮换策略进行轮换。
配置 APISIX
配置一条路由,在将请求转发到公共 HTTP 请求与响应服务 httpbin.org 之前接受 Auth0 Bearer Token。/anything/m2m/* 端点会返回请求详情以供验证。
选择使用 Admin API 或 ADC 配置路由。
- Admin API
- ADC
创建一条使用 Auth0 的 JWKS 在本地验证 Bearer Token 的路由:
curl "http://127.0.0.1:9180/apisix/admin/routes/auth0-m2m" -X PUT \
--data-binary @- <<EOF
{
"uri": "/anything/m2m/*",
"plugins": {
"openid-connect": {
"client_id": "$AUTH0_API_AUDIENCE",
"discovery": "$AUTH0_DISCOVERY",
"bearer_only": true,
"use_jwks": true,
"claim_validator": {
"audience": {
"required": true,
"match_with_client_id": true
}
},
"required_scopes": ["read:messages"],
"set_access_token_header": false,
"set_id_token_header": false,
"set_userinfo_header": false
},
"proxy-rewrite": {
"headers": {
"remove": ["Authorization"]
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}
EOF
client_id 设置为 Auth0 API 标识符,以便 APISIX 将其与 Token 的受众进行比较。M2M 应用的客户端 ID 仅用于请求访问 Token。
❶ bearer_only 和 use_jwks:要求使用 Bearer 访问 Token,并使用 Auth0 发布的公钥在本地验证 JWT 签名。
❷ claim_validator.audience:要求 Token 的 aud 声明与配置为 client_id 的 Auth0 API 标识符匹配。
❸ required_scopes:要求访问 Token 包含授予 M2M 应用的权限。
❹ set_access_token_header、set_id_token_header 和 set_userinfo_header:设置为 false,防止 APISIX 将访问 Token、ID Token 和 Token 声明添加到上游请求头。
❺ proxy-rewrite.headers.remove:在 APISIX 代理请求前移除原始 Bearer Token。如果上游应用必须接收访问 Token 或其声明,请复查这些请求头设置。
使用相同的路由配置创建 adc.yaml 文件:
services:
- name: httpbin
routes:
- name: auth0-m2m
uris:
- /anything/m2m/*
plugins:
openid-connect:
client_id: "${AUTH0_API_AUDIENCE}"
discovery: "${AUTH0_DISCOVERY}"
bearer_only: true
use_jwks: true
claim_validator:
audience:
required: true
match_with_client_id: true
required_scopes:
- read:messages
set_access_token_header: false
set_id_token_header: false
set_userinfo_header: false
proxy-rewrite:
headers:
remove:
- Authorization
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
client_id 设置为 Auth0 API 标识符,以便 APISIX 将其与 Token 的受众进行比较。M2M 应用的客户端 ID 仅用于请求访问 Token。
❶ bearer_only 和 use_jwks:要求使用 Bearer 访问 Token,并使用 Auth0 发布的公钥在本地验证 JWT 签名。
❷ claim_validator.audience:要求 Token 的 aud 声明与配置为 client_id 的 Auth0 API 标识符匹配。
❸ required_scopes:要求访问 Token 包含授予 M2M 应用的权限。
❹ set_access_token_header、set_id_token_header 和 set_userinfo_header:设置为 false,防止 APISIX 将访问 Token、ID Token 和 Token 声明添加到上游请求头。
❺ proxy-rewrite.headers.remove:在 APISIX 代理请求前移除原始 Bearer Token。如果上游应用必须接收访问 Token 或其声明,请复查这些请求头设置。
将配置同步到 APISIX:
adc sync -f adc.yaml
验证 M2M 授权
从 Auth0 为受保护的 API 请求访问 Token:
export AUTH0_ACCESS_TOKEN="$(
curl -sS "https://${AUTH0_DOMAIN}/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${AUTH0_M2M_CLIENT_ID}" \
--data-urlencode "client_secret=${AUTH0_M2M_CLIENT_SECRET}" \
--data-urlencode "audience=${AUTH0_API_AUDIENCE}" \
--data-urlencode "grant_type=client_credentials" | \
jq -er '.access_token'
)"
将访问 Token 发送到受保护的路由:
curl -i "http://127.0.0.1:9080/anything/m2m/get" \
-H "Authorization: Bearer ${AUTH0_ACCESS_TOKEN}"
返回 HTTP/1.1 200 OK 表示 APISIX 已接受为受保护 API 颁发且包含所需权限的 Token。响应正文应包含类似以下内容的字段:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "localhost",
"User-Agent": "curl/8.7.1",
"X-Amzn-Trace-Id": "Root=1-...",
"X-Forwarded-Host": "localhost:9080"
},
"json": null,
"method": "GET",
"origin": "192.168.155.1, xxx.xxx.xxx.xxx",
"url": "http://localhost:9080/anything/m2m/get"
}
请求头值和报告的源地址会因客户端及网络环境而异。由于路由阻止相关信息被代理,上游请求头不应包含 Authorization、X-Access-Token、X-Id-Token 或 X-Userinfo。
发送不带 Token 的相同请求:
curl -i "http://127.0.0.1:9080/anything/m2m/get"
由于该路由要求 Bearer Token,APISIX 应返回 HTTP/1.1 401 Unauthorized。
后续步骤
你已配置 APISIX,使用 Auth0 的访问 Token 和权限为 M2M 请求授权。如需配置基于浏览器的用户身份认证,请参阅使用 Auth0 配置 SSO。有关更多 Token 验证和授权选项,请参阅 openid-connect 插件参考。