配置数据库策略以实现行级过滤
数据墙DBW支持数据库策略,可根据你定义的表达式过滤查询结果。数据库会将这些策略作为查询谓词(WHERE 子句)来执行,因此用户只能看到他们被允许访问的数据。
何时使用数据库策略
当你需要以下能力时,数据库策略非常适合:
- 基于字段值限制记录(例如
status eq 'published') - 基于已认证用户的声明过滤数据(例如
@claims.userId) - 在不修改存储过程或视图的情况下实现行级访问控制
- 针对不同角色应用不同的过滤规则
NOTE
文档数据库场景当前不支持数据库策略。
支持的动作
数据库策略适用于以下动作:
| 动作 | 是否支持 | 工作方式 |
|---|---|---|
read | ✔️ Yes | 为 SELECT 查询增加 WHERE 谓词 |
update | ✔️ Yes | 为 UPDATE 语句增加 WHERE 谓词 |
delete | ✔️ Yes | 为 DELETE 语句增加 WHERE 谓词 |
create | ❌ No | INSERT 语句不支持 WHERE 谓词 |
execute | ❌ No | 存储过程不支持查询谓词 |
先决条件
- 已安装数据墙DBW CLI(请参阅安装指南)
- 至少包含一个实体的现有配置文件
- 已配置身份验证提供程序(策略要求请求已通过身份验证)
快速参考
| 概念 | 语法 | 示例 |
|---|---|---|
| 字段引用 | @item.<field> | @item.status |
| 声明引用 | @claims.<type> | @claims.userId |
| 相等比较 | eq | @item.ownerId eq @claims.userId |
| 不等比较 | ne | @item.status ne 'draft' |
| 比较运算 | gt、ge、lt、le | @item.price lt 100 |
| 逻辑与 | and | @item.active eq true and @item.published eq true |
| 逻辑或 | or | @item.role eq 'admin' or @item.role eq 'editor' |
步骤 1:定义策略表达式
数据库策略使用 OData 风格谓词。表达式必须计算为 true,对应数据行才会被包含在结果中。
使用 @item 引用字段
使用 @item.<field> 引用实体字段。如果你把数据库列映射成了不同的 API 字段名,请使用映射后的名称。
@item.status eq 'published'使用 @claims 引用声明
使用 @claims.<claimType> 将已认证用户令牌中的声明值注入表达式。运行时,数据墙DBW会把声明值替换进表达式中。
@item.ownerId eq @claims.userIdIMPORTANT
如果策略中引用的声明不存在于令牌中,请求会以 403 Forbidden 被拒绝。
复合表达式
使用 and 或 or 组合多个条件:
@item.ownerId eq @claims.userId and @item.status ne 'deleted'步骤 2:把策略加入实体配置
策略按角色和动作定义在实体权限中:
配置文件格式
{
"entities": {
"<entity-name>": {
"permissions": [
{
"role": "<role-name>",
"actions": [
{
"action": "read",
"policy": {
"database": "<predicate-expression>"
}
}
]
}
]
}
}
}示例:用户只能读取自己的记录
{
"entities": {
"Order": {
"source": "dbo.Orders",
"permissions": [
{
"role": "customer",
"actions": [
{
"action": "read",
"policy": {
"database": "@item.customerId eq @claims.userId"
}
}
]
}
]
}
}
}示例:多个动作使用同一策略
将同一策略应用于 read、update 和 delete:
{
"entities": {
"Document": {
"source": "dbo.Documents",
"permissions": [
{
"role": "author",
"actions": [
{
"action": "read",
"policy": {
"database": "@item.authorId eq @claims.sub"
}
},
{
"action": "update",
"policy": {
"database": "@item.authorId eq @claims.sub"
}
},
{
"action": "delete",
"policy": {
"database": "@item.authorId eq @claims.sub"
}
}
]
}
]
}
}
}示例:固定值过滤
按固定值过滤,而不是按声明值过滤:
{
"entities": {
"Article": {
"source": "dbo.Articles",
"permissions": [
{
"role": "Anonymous",
"actions": [
{
"action": "read",
"policy": {
"database": "@item.status eq 'published'"
}
}
]
}
]
}
}
}步骤 3:使用 CLI 配置
你可以通过 dab update 命令在 CLI 中添加数据库策略:
Bash
dab update Order \
--permissions "customer:read" \
--policy-database "@item.customerId eq @claims.userId"Command Prompt
dab update Order ^
--permissions "customer:read" ^
--policy-database "@item.customerId eq @claims.userId"TIP
当策略表达式中包含特殊字符时,请根据你的 shell 使用适当的引号包裹整个表达式。
策略是如何被处理的
当请求到达时,数据墙DBW会:
- 从
X-MS-API-ROLE标头或系统角色判定最终生效角色 - 查找该实体、该角色、该动作对应的策略
- 通过把
@claims.<type>替换成令牌中的实际值来完成claims 替换 - 将表达式按 OData
$filter语法进行解析 - 生成数据库查询谓词,并将它们附加到最终数据库查询中
例如,如果策略为 @item.ownerId eq @claims.userId,且令牌中包含 userId: "user123",那么生成的 SQL 会包含:
WHERE [ownerId] = 'user123'Claims 替换
数据墙DBW会从已认证用户的 JSON Web Token(JWT)或身份主体中提取声明。常见声明包括:
| 声明 | 说明 | 示例值 |
|---|---|---|
sub | Subject 标识符(用户 ID) | ffffffff-eeee-dddd-cccc-bbbbbbbbbbb0 |
userId | 自定义用户标识符 | user123 |
email | 用户电子邮件地址 | user@example.com |
name | 用户显示名称 | Jane Doe |
roles | 角色成员关系(数组) | ["reader", "editor"] |
WARNING
如果策略中引用的声明不存在于令牌中,数据墙DBW会以 403 Forbidden 拒绝该请求。请确保你的身份提供程序输出了所有必需声明。
与字段限制结合使用
策略可以与字段级访问控制配合使用。你可以同时限制角色可访问的行和列:
{
"role": "auditor",
"actions": [
{
"action": "read",
"fields": {
"include": ["id", "amount", "status"],
"exclude": ["internalNotes"]
},
"policy": {
"database": "@item.status eq 'completed'"
}
}
]
}限制
| 限制 | 说明 |
|---|---|
不支持 create 动作 | INSERT 语句不支持 WHERE 谓词 |
不支持 execute 动作 | 存储过程不接受查询谓词 |
| 不支持文档数据库场景 | 当前不支持数据库策略 |
| 不支持命名授权策略 | 数据墙DBW 不支持 ASP.NET / HotChocolate 风格的命名策略 |
故障排查
找不到声明(403 Forbidden)
如果请求因为 403 Forbidden 失败,请检查:
- 该声明是否存在于访问令牌中
- 声明名称是否完全匹配(区分大小写)
- 身份提供程序是否已配置为输出该声明
策略未生效
如果结果没有被正确过滤:
- 确认角色名称是否与
X-MS-API-ROLE标头值匹配 - 确认目标动作(read、update、delete)是否定义了策略
- 检查身份验证是否已正确配置,并且该请求确实是已认证请求
语法错误
如果引擎报告策略解析错误:
- 确认表达式使用的是 OData 语法(
eq、ne、and、or) - 检查字段名使用的是映射后的 API 名称,而不是数据库列名
- 确保字符串值使用单引号括起来
