排查权限问题
权限问题(401 Unauthorized 和 403 Forbidden)是数据墙DBW 最常见的故障类型。本文档提供系统化的诊断方法,帮助你快速定位是认证配置问题还是授权规则问题。
第一步:区分 401 和 403
| 状态码 | 含义 | 故障方向 |
|---|---|---|
401 Unauthorized | 身份验证失败——引擎无法确认请求方的身份 | 认证配置 |
403 Forbidden | 身份验证通过,但当前角色无权执行该操作 | 权限配置 |
诊断行动: 首先确认你遇到的是 401 还是 403。两者的排查方向完全不同。
401 排查:认证失败
检查认证提供程序配置
bash
dab configure --show-effective-permissions
# 确认 provider 设置json
{
"runtime": {
"host": {
"authentication": {
"provider": "Custom"
}
}
}
}| Provider | 预期行为 |
|---|---|
Unauthenticated | 不验证令牌——不应该出现 401。如果出现,检查是否有反向代理或中间件干涉了认证头 |
Custom | 验证 JWT 令牌——需要有效的 Authorization: Bearer <token> 头 |
Simulator | 开发模式下不验证——不应该出现 401 |
JWT 令牌验证失败(Custom 模式)
引擎验证令牌时逐项检查以下内容,任一失败返回 401:
| 检查项 | 配置字段 | 诊断方法 |
|---|---|---|
| 签名有效 | jwt.issuer(用于发现 JWKS) | 确认 /.well-known/openid-configuration 可访问 |
iss 声明匹配 | jwt.issuer | 解码 JWT,对比 iss 与配置 |
aud 声明匹配 | jwt.audience | 解码 JWT,对比 aud 与配置 |
| 令牌未过期 | — | 检查 exp 时间戳 |
| 令牌已生效 | — | 检查 nbf 时间戳 |
诊断步骤:
- 在 jwt.io 解码令牌,查看
iss、aud、exp、nbf。 - 与
dab-config.json中的配置对比。 - 确认身份提供程序的 OpenID 配置端点可访问。
- 确认系统时间与身份提供程序时间同步(
exp/nbf依赖时钟)。
Unauthenticated 模式下的 401
Unauthenticated 模式下引擎不执行任何令牌验证,理论上不应返回 401。如果出现,可能原因:
- 反向代理或 API 网关在请求到达数据墙DBW 之前拦截了请求并返回 401。
- 负载均衡器层面的认证配置。
- 数据墙DBW 前还有其他服务处理了认证。
诊断步骤: 直接从数据墙DBW 的内部网络地址调用 API,排除中间层干扰。
403 排查:权限拒绝
确认最终生效角色
引擎每次请求只在一个角色的上下文下评估。确认实际使用的角色:
| 请求特征 | 最终角色 |
|---|---|
无 Authorization 头(Unauthenticated 模式) | Anonymous |
有有效令牌,无 X-MS-API-ROLE 头 | Authenticated |
有有效令牌 + X-MS-API-ROLE: <role> | <role>(需令牌中包含该角色) |
有有效令牌 + X-MS-API-ROLE: <role> 但令牌中无此角色 | 拒绝(403) |
诊断步骤: 在请求中显式设置 X-MS-API-ROLE 头,确认你期望的角色是否被引擎接收。
运行有效权限查看
bash
dab configure --show-effective-permissions输出示例:
text
Entity: Book
Role: anonymous | Actions: Read
Role: authenticated | Actions: Read (inherited from: anonymous)
Unconfigured roles inherit from: anonymous检查:
- 目标实体是否存在你期望的角色权限块。
- 角色是否通过继承获得权限。
- 操作名称是否正确(
read不是get,create不是insert)。
常见 403 原因
| 原因 | 表现 | 解决 |
|---|---|---|
| 实体未配置该角色的权限 | 该角色对实体无任何 permissions 条目 | 添加权限或确保角色能通过继承获得 |
| 角色名大小写不匹配 | 配置中是 Editor,令牌中是 editor | 统一大小写 |
| 操作名错误 | 配置 "actions": ["read"] 但执行了 POST | 确认操作名与权限一致 |
| Unauthenticated 模式 + 命名角色 | 所有请求都是 anonymous,命名角色不生效 | 切换认证模式或只为 anonymous 配置权限 |
| 通配符被误用 | 存储过程的 * 只等于 execute,不等于 CRUD | 确认操作与实体类型匹配 |
| 策略中引用的声明不存在 | 令牌中缺少 @claims.xxx 引用的声明 | 配置身份提供程序输出缺失的声明 |
字段级 403
如果请求访问了被排除的字段:
- REST
$select引用被排除字段 →400 Bad Request(不是 403)。 - GraphQL 查询被排除字段 → GraphQL 错误。
- 不传
$select时,被排除字段自动不出现在响应中。
诊断步骤: 检查该角色是否配置了 fields.exclude,确认请求中没有引用被排除的字段。
策略导致的 403
如果配置了数据库策略且策略引用了 JWT 声明:
json
{
"policy": {
"database": "@item.ownerId eq @claims.userId"
}
}当令牌中不存在 userId 声明时——引擎直接返回 403,不执行查询。
诊断步骤:
- 解码 JWT 令牌确认声明存在。
- 确认声明名拼写与策略中完全一致(区分大小写)。
- 身份提供程序可能需要在令牌中显式包含该声明。
角色继承的意外行为
角色继承可能带来两个意外:
| 意外 | 原因 |
|---|---|
| 认为某个角色应该有权限但被 403 | 该角色和继承链上的角色都没有权限块 |
| 认为某个角色不应该有权限但却能访问 | 该角色从 anonymous / authenticated 继承了权限 |
诊断步骤: 运行 dab configure --show-effective-permissions,逐实体、逐角色查看继承结果,确认是否符合预期。
系统化排查流程
text
1. 确认 HTTP 状态码
├── 401 → 排查认证
│ ├── 确认 provider 配置
│ ├── 检查 JWT 令牌(Custom 模式)
│ └── 排除中间层干扰(Unauthenticated 模式)
└── 403 → 排查授权
├── 确认最终生效角色(X-MS-API-ROLE?默认?)
├── 运行 dab configure --show-effective-permissions
├── 检查实体 permissions 配置
├── 检查 fields.exclude
├── 检查 policy 中的 @claims 是否存在
└── 确认角色继承是否符合预期