配置自定义 JWT 身份验证(Okta、Auth0)
数据墙DBW通过 Custom 身份验证提供程序支持第三方身份提供程序,并使用 JSON Web Token(JWT)验证。若你的组织使用 Okta、Auth0 或其他符合 OAuth 2.0 / OpenID Connect 的身份提供程序,应采用这种方式。
身份验证流程
使用自定义身份提供程序时,客户端应用负责用户身份验证,然后将访问令牌发送给数据墙DBW:
| 阶段 | 发生的事情 |
|---|---|
| 用户认证 | 用户通过身份提供程序(Okta、Auth0 等)登录 |
| 获取令牌 | 客户端应用从身份提供程序获取访问令牌 |
| 调用 API | 客户端将令牌通过 Authorization 标头发送给数据墙DBW |
| 验证 | 数据墙DBW验证 JWT(issuer、audience、签名) |
| 授权 | 数据墙DBW提取角色并评估权限 |
先决条件
- 你在身份提供程序(Okta、Auth0 等)中的帐户
- 一个已在身份提供程序中注册的应用
- 已安装数据墙DBW CLI(请参阅安装指南)
- 至少包含一个实体的现有
dab-config.json
快速参考
| 设置 | 值 |
|---|---|
| Provider | Custom |
| 验证所需 | iss、aud、exp、有效签名 |
| 授权所需 | 包含所选角色的 roles 声明 |
| 令牌标头 | Authorization: Bearer <token> |
| 角色声明类型 | roles(固定,不可配置) |
| 角色选择标头 | X-MS-API-ROLE |
步骤 1:配置你的身份提供程序
具体步骤取决于你的提供程序。这里列出你需要收集的关键值。
需要收集的值
| 值 | 获取位置 | 用途 |
|---|---|---|
| Issuer URL | 提供程序文档或 OAuth 元数据终结点 | 数据墙DBW中的 jwt.issuer(用作 JWT Authority) |
| Audience | 你的应用客户端 ID 或自定义 API 标识符 | 数据墙DBW中的 jwt.audience |
NOTE
数据墙DBW使用配置中的 jwt.issuer 作为 JWT 的 Authority。签名密钥会通过标准 OpenID Connect 元数据自动发现(通常是 <issuer>/.well-known/openid-configuration)。
Okta 示例
- 登录 Okta Admin Console。
- 进入 Applications > Applications。
- 创建或选择一个应用。
- 记录 Client ID(将它作为 audience)。
- 你的 issuer 通常是
https://<your-domain>.okta.com。
Auth0 示例
- 登录 Auth0 Dashboard。
- 进入 Applications > APIs。
- 创建或选择一个 API。
- 记录 Identifier(将它作为 audience)。
- 你的 issuer 一般为
https://<your-tenant>.auth0.com/。
IMPORTANT
数据墙DBW在基于角色的授权中固定使用 roles 作为声明类型,这个值不能配置。如果你的身份提供程序把角色输出到别的声明中(例如 groups 或 permissions),你必须配置身份提供程序额外输出一个 roles 声明,或在登录后动作中把这些值复制到 roles 声明里。
步骤 2:配置数据墙DBW
将身份验证提供程序设为 Custom,并配置 JWT 相关设置:
CLI
Bash
# 设置身份验证提供程序
dab configure \
--runtime.host.authentication.provider Custom
# 设置预期 audience
dab configure \
--runtime.host.authentication.jwt.audience "<your-api-identifier>"
# 设置预期 issuer
dab configure \
--runtime.host.authentication.jwt.issuer "https://<your-issuer>/"Command Prompt
REM 设置身份验证提供程序
dab configure ^
--runtime.host.authentication.provider Custom
REM 设置预期 audience
dab configure ^
--runtime.host.authentication.jwt.audience "<your-api-identifier>"
REM 设置预期 issuer
dab configure ^
--runtime.host.authentication.jwt.issuer "https://<your-issuer>/"生成的配置
{
"runtime": {
"host": {
"authentication": {
"provider": "Custom",
"jwt": {
"audience": "<your-api-identifier>",
"issuer": "https://<your-issuer>/"
}
}
}
}
}步骤 3:配置实体权限
为身份提供程序分配的角色定义权限:
CLI
Bash
# 允许已验证用户读取
dab update Book \
--permissions "authenticated:read"
# 允许具有 admin 角色的用户拥有全部权限
dab update Book \
--permissions "admin:*"Command Prompt
REM 允许已验证用户读取
dab update Book ^
--permissions "authenticated:read"
REM 允许具有 admin 角色的用户拥有全部权限
dab update Book ^
--permissions "admin:*"生成的配置
{
"entities": {
"Book": {
"source": "dbo.Books",
"permissions": [
{
"role": "authenticated",
"actions": ["read"]
},
{
"role": "admin",
"actions": ["*"]
}
]
}
}
}步骤 4:在身份提供程序中配置角色
数据墙DBW要求角色位于 roles 声明中。你必须配置身份提供程序输出这个声明。
Okta:将组作为角色输出
- 在 Okta Admin Console 中,进入 Security > API。
- 选择你的授权服务器。
- 进入 Claims 选项卡。
- 添加一个声明:
- Name:
roles - Include in token type:Access Token
- Value type:Groups
- Filter:选择要包含的组
- Name:
Auth0:使用 Action 添加角色
- 在 Auth0 Dashboard 中,进入 Actions > Library。
- 创建一个新的 Action(Post Login trigger)。
- 添加以下代码以写入角色:
exports.onExecutePostLogin = async (event, api) => {
const roles = event.authorization?.roles || [];
if (roles.length > 0) {
api.accessToken.setCustomClaim('roles', roles);
}
};- 部署该 Action,并将其加入 Login flow。
TIP
关于如何在 Okta 中定制 JWT 声明,可参考 Customize tokens returned from Okta。
步骤 5:测试配置
启动数据墙DBW:
bashdab start从你的身份提供程序获取一个令牌。你可以使用提供程序的 SDK,或使用 Postman 之类的工具。
在 jwt.io 检查该令牌,确认:
aud声明与配置的 audience 匹配iss声明与配置的 issuer 匹配roles声明包含预期值
调用 API:
bashcurl -X GET "http://localhost:5000/api/Book" \ -H "Authorization: Bearer <your-token>"若要使用自定义角色,请附加
X-MS-API-ROLE标头:bashcurl -X GET "http://localhost:5000/api/Book" \ -H "Authorization: Bearer <your-token>" \ -H "X-MS-API-ROLE: admin"
JWT 验证细节
数据墙DBW会对 JWT 做以下检查:
| 检查项 | 说明 |
|---|---|
| Signature | 使用通过配置的 jwt.issuer authority 自动发现的签名密钥完成验证(OpenID Connect 元数据或 JWKS) |
| Issuer | 必须与 jwt.issuer 配置完全匹配 |
| Audience | 必须与 jwt.audience 配置完全匹配 |
| Expiration | 令牌不得过期(exp 声明) |
| Not Before | 若存在 nbf 声明,令牌必须已经生效 |
故障排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
401 Unauthorized | issuer 不匹配 | 检查 iss 声明是否完全一致(包括末尾斜杠) |
401 Unauthorized | audience 不匹配 | 检查 aud 声明是否与配置值一致 |
401 Unauthorized | 令牌已过期 | 获取新令牌 |
401 Unauthorized | 元数据不可访问 | 确保数据墙DBW可访问 <issuer>/.well-known/openid-configuration |
403 Forbidden | 角色不在令牌中 | 在身份提供程序中添加该角色 |
403 Forbidden | 没有 roles 声明 | 配置身份提供程序输出 roles 声明 |
403 Forbidden | 声明名称错误 | 数据墙DBW固定使用 roles,不可配置成别的名称 |
IMPORTANT
数据墙DBW当前对所有角色检查都固定使用 roles 声明类型。这个值是硬编码的,不能改成 groups、permissions 或其他声明名。请在你的身份提供程序中确保角色输出到名为 roles 的声明中。
常见 issuer 格式
| 提供程序 | issuer 格式 |
|---|---|
| Okta | https://<domain>.okta.com 或 https://<domain>.okta.com/oauth2/default |
| Auth0 | https://<tenant>.auth0.com/(注意尾部斜杠) |
| Azure AD B2C | https://<tenant>.b2clogin.com/<tenant-id>/v2.0/ |
| Keycloak | https://<host>/realms/<realm> |
完整配置示例
Okta 配置
{
"$schema": "https://github.com/Azure/data-api-builder/releases/latest/download/数据墙DBW.draft.schema.json",
"data-source": {
"database-type": "mssql",
"connection-string": "@env('SQL_CONNECTION_STRING')"
},
"runtime": {
"host": {
"authentication": {
"provider": "Custom",
"jwt": {
"audience": "0oa1234567890abcdef",
"issuer": "https://dev-12345.okta.com"
}
}
}
},
"entities": {
"Book": {
"source": "dbo.Books",
"permissions": [
{
"role": "authenticated",
"actions": ["read"]
},
{
"role": "editor",
"actions": ["create", "read", "update"]
}
]
}
}
}Auth0 配置
{
"$schema": "https://github.com/Azure/data-api-builder/releases/latest/download/数据墙DBW.draft.schema.json",
"data-source": {
"database-type": "mssql",
"connection-string": "@env('SQL_CONNECTION_STRING')"
},
"runtime": {
"host": {
"authentication": {
"provider": "Custom",
"jwt": {
"audience": "https://my-api.example.com",
"issuer": "https://my-tenant.auth0.com/"
}
}
}
},
"entities": {
"Book": {
"source": "dbo.Books",
"permissions": [
{
"role": "authenticated",
"actions": ["read"]
},
{
"role": "admin",
"actions": ["*"]
}
]
}
}
}