Skip to content

配置数据库策略以实现行级过滤

数据墙DBW支持数据库策略,可根据你定义的表达式过滤查询结果。数据库会将这些策略作为查询谓词(WHERE 子句)来执行,因此用户只能看到他们被允许访问的数据。

展示策略应用过程的时序图。

何时使用数据库策略

当你需要以下能力时,数据库策略非常适合:

  • 基于字段值限制记录(例如 status eq 'published'
  • 基于已认证用户的声明过滤数据(例如 @claims.userId
  • 在不修改存储过程或视图的情况下实现行级访问控制
  • 针对不同角色应用不同的过滤规则

NOTE

文档数据库场景当前不支持数据库策略。

支持的动作

数据库策略适用于以下动作:

动作是否支持工作方式
read✔️ Yes为 SELECT 查询增加 WHERE 谓词
update✔️ Yes为 UPDATE 语句增加 WHERE 谓词
delete✔️ Yes为 DELETE 语句增加 WHERE 谓词
create❌ NoINSERT 语句不支持 WHERE 谓词
execute❌ No存储过程不支持查询谓词

先决条件

  • 已安装数据墙DBW CLI(请参阅安装指南
  • 至少包含一个实体的现有配置文件
  • 已配置身份验证提供程序(策略要求请求已通过身份验证)

快速参考

概念语法示例
字段引用@item.<field>@item.status
声明引用@claims.<type>@claims.userId
相等比较eq@item.ownerId eq @claims.userId
不等比较ne@item.status ne 'draft'
比较运算gtgeltle@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 字段名,请使用映射后的名称。

text
@item.status eq 'published'

使用 @claims 引用声明

使用 @claims.<claimType> 将已认证用户令牌中的声明值注入表达式。运行时,数据墙DBW会把声明值替换进表达式中。

text
@item.ownerId eq @claims.userId

IMPORTANT

如果策略中引用的声明不存在于令牌中,请求会以 403 Forbidden 被拒绝。

复合表达式

使用 andor 组合多个条件:

text
@item.ownerId eq @claims.userId and @item.status ne 'deleted'

步骤 2:把策略加入实体配置

策略按角色和动作定义在实体权限中:

配置文件格式

json
{
  "entities": {
    "<entity-name>": {
      "permissions": [
        {
          "role": "<role-name>",
          "actions": [
            {
              "action": "read",
              "policy": {
                "database": "<predicate-expression>"
              }
            }
          ]
        }
      ]
    }
  }
}

示例:用户只能读取自己的记录

json
{
  "entities": {
    "Order": {
      "source": "dbo.Orders",
      "permissions": [
        {
          "role": "customer",
          "actions": [
            {
              "action": "read",
              "policy": {
                "database": "@item.customerId eq @claims.userId"
              }
            }
          ]
        }
      ]
    }
  }
}

示例:多个动作使用同一策略

将同一策略应用于 read、update 和 delete:

json
{
  "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"
              }
            }
          ]
        }
      ]
    }
  }
}

示例:固定值过滤

按固定值过滤,而不是按声明值过滤:

json
{
  "entities": {
    "Article": {
      "source": "dbo.Articles",
      "permissions": [
        {
          "role": "Anonymous",
          "actions": [
            {
              "action": "read",
              "policy": {
                "database": "@item.status eq 'published'"
              }
            }
          ]
        }
      ]
    }
  }
}

步骤 3:使用 CLI 配置

你可以通过 dab update 命令在 CLI 中添加数据库策略:

Bash

bash
dab update Order \
  --permissions "customer:read" \
  --policy-database "@item.customerId eq @claims.userId"

Command Prompt

cmd
dab update Order ^
  --permissions "customer:read" ^
  --policy-database "@item.customerId eq @claims.userId"

TIP

当策略表达式中包含特殊字符时,请根据你的 shell 使用适当的引号包裹整个表达式。

策略是如何被处理的

当请求到达时,数据墙DBW会:

  1. X-MS-API-ROLE 标头或系统角色判定最终生效角色
  2. 查找该实体、该角色、该动作对应的策略
  3. 通过把 @claims.<type> 替换成令牌中的实际值来完成claims 替换
  4. 将表达式按 OData $filter 语法进行解析
  5. 生成数据库查询谓词,并将它们附加到最终数据库查询中

例如,如果策略为 @item.ownerId eq @claims.userId,且令牌中包含 userId: "user123",那么生成的 SQL 会包含:

sql
WHERE [ownerId] = 'user123'

Claims 替换

数据墙DBW会从已认证用户的 JSON Web Token(JWT)或身份主体中提取声明。常见声明包括:

声明说明示例值
subSubject 标识符(用户 ID)ffffffff-eeee-dddd-cccc-bbbbbbbbbbb0
userId自定义用户标识符user123
email用户电子邮件地址user@example.com
name用户显示名称Jane Doe
roles角色成员关系(数组)["reader", "editor"]

WARNING

如果策略中引用的声明不存在于令牌中,数据墙DBW会以 403 Forbidden 拒绝该请求。请确保你的身份提供程序输出了所有必需声明。

与字段限制结合使用

策略可以与字段级访问控制配合使用。你可以同时限制角色可访问的行和列:

json
{
  "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 语法(eqneandor
  • 检查字段名使用的是映射后的 API 名称,而不是数据库列名
  • 确保字符串值使用单引号括起来

相关内容

数据墙DBW 产品文档与开发指南。