签入版本
This commit is contained in:
@@ -1,132 +1,68 @@
|
||||
# 5.9 数据权限
|
||||
# 5.10 数据权限
|
||||
|
||||
:::tip 概述
|
||||
数据权限控制用户能看到哪些数据,基于角色的 `data_scope` 字段进行过滤。支持三种范围:全部数据、本部门数据、仅本人数据。
|
||||
数据权限是**行级过滤**:按角色的数据范围档位,在查询链上追加部门/本人条件。它与功能权限(Authz,能不能访问接口)严格分层——一个管"进不进得了门",一个管"看得到哪些数据"。
|
||||
:::
|
||||
|
||||
## 三种范围
|
||||
## 四个档位
|
||||
|
||||
| 档位 | 含义 | 行级条件 |
|
||||
|---|---|---|
|
||||
| 1 | 全部 | 租户隔离之内不过滤 |
|
||||
| 2 | 本部门及以下 | dept_id IN(自身部门 + 全部子孙部门) |
|
||||
| 3 | 本部门 | dept_id = 自身部门 |
|
||||
| 4 | 仅本人 | id = 自身用户 ID |
|
||||
|
||||
档位存在角色上(role.data_scope),多角色用户在身份装配层**取最宽松**。
|
||||
|
||||
## 生效链路
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ data_scope = 1 │
|
||||
│ 全部数据(不过滤) │
|
||||
│ │
|
||||
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
|
||||
│ │ A │ │ B │ │ C │ │ D │ │ E │ ← 所有部门所有人的数据 │
|
||||
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ data_scope = 2 │
|
||||
│ 本部门数据 │
|
||||
│ │
|
||||
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
|
||||
│ │ A │ │ B │ │███│ │ D │ │ E │ ← 只看到本部门数据 │
|
||||
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ data_scope = 3 │
|
||||
│ 仅本人数据 │
|
||||
│ │
|
||||
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
|
||||
│ │ A │ │ B │ │███│ │ D │ │ E │ ← 只看到自己创建的数据 │
|
||||
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
身份装配(LoadIdentity)→ ctx 携带数据范围档位 + deptID + userID
|
||||
↓
|
||||
ModuleSpec 声明挂接:DataScope: ApplyDataScope("dept_id")
|
||||
↓
|
||||
applyFilters 固定顺序最后一步执行(先软删/租户/查询条件,后数据范围)
|
||||
↓
|
||||
Page / List / 导出自动生效
|
||||
```
|
||||
|
||||
## 配置方式
|
||||
Detail / Update / Delete **不过滤**——由权限节点与租户隔离兜底(拿到 ID 越权访问单条的场景由权限码控制)。
|
||||
|
||||
在 Logic 中配置数据权限字段即可启用:
|
||||
## 挂接示例
|
||||
|
||||
```php
|
||||
class UserLogic extends BaseTenantLogic
|
||||
{
|
||||
/**
|
||||
* 数据权限:部门关联字段名(用于按部门过滤)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $dataScopeDeptField = 'dept_id';
|
||||
}
|
||||
|
||||
class ArticleLogic extends BaseTenantLogic
|
||||
{
|
||||
/**
|
||||
* 数据权限:归属字段名(用于按创建人过滤)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $dataScopeUserField = 'create_user';
|
||||
```go
|
||||
// internal/service 内需数据权限的模块声明(以 userSpec 为例)
|
||||
var userSpec = ModuleSpec[...]{
|
||||
// ...
|
||||
DataScope: ApplyDataScope("dept_id"), // 行上的部门列名
|
||||
}
|
||||
```
|
||||
|
||||
## 实现机制
|
||||
## 适用边界
|
||||
|
||||
```php
|
||||
// app/BaseLogic.php
|
||||
| 适用 | 不适用 |
|
||||
|---|---|
|
||||
| 以用户为主体、行上有 dept_id 列的表(user 等) | 无部门列的行表(内容模块等)——不挂接本工厂 |
|
||||
|
||||
protected function applyDataScope($model)
|
||||
{
|
||||
// 未配置数据权限字段则跳过
|
||||
if (empty($this->dataScopeUserField) && empty($this->dataScopeDeptField)) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
$userInfo = request()->userInfo ?? null;
|
||||
$uid = $userInfo->uid ?? 0;
|
||||
$roleId = $userInfo->role_id ?? 0;
|
||||
|
||||
// 获取角色的数据权限范围
|
||||
$dataScope = $this->getRoleDataScope($roleId);
|
||||
|
||||
// 1=全部数据,不做过滤
|
||||
if ($dataScope == 1) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
// 2=本部门数据
|
||||
if ($dataScope == 2 && $this->dataScopeDeptField) {
|
||||
$deptId = $this->getUserDeptId($uid);
|
||||
if ($deptId) {
|
||||
$model = $model->where($this->dataScopeDeptField, $deptId);
|
||||
}
|
||||
return $model;
|
||||
}
|
||||
|
||||
// 3=仅本人数据
|
||||
if ($dataScope == 3 && $this->dataScopeUserField) {
|
||||
$model = $model->where($this->dataScopeUserField, $userInfo->username);
|
||||
return $model;
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
```
|
||||
|
||||
## 角色配置
|
||||
|
||||
在角色管理中设置 `data_scope` 字段:
|
||||
|
||||
| 值 | 范围 | 适用场景 |
|
||||
|----|------|----------|
|
||||
| 1 | 全部数据 | 管理层、超级管理员 |
|
||||
| 2 | 本部门数据 | 部门经理 |
|
||||
| 3 | 仅本人数据 | 普通员工 |
|
||||
|
||||
## 缓存说明
|
||||
|
||||
角色的数据权限范围带 1 小时缓存(`role_data_scope_{roleId}`)。修改角色权限后需等待缓存过期或手动清除。
|
||||
|
||||
## 超级管理员
|
||||
|
||||
`uid=1` 的超级管理员不受数据权限限制,始终看到全部数据。详见 [RBAC 权限管理](/zh/core/rbac.html)。
|
||||
豁免机制:平台级身份与特定场景经 dataScopeBypass 豁免过滤(如超管全量可见)。
|
||||
|
||||
## 与租户隔离的关系
|
||||
|
||||
数据权限和租户隔离是两个独立的维度:
|
||||
- **租户隔离**:按 `tenant_id` 过滤,不同租户数据完全隔离
|
||||
- **数据权限**:在同一租户内,按部门或创建人进一步过滤
|
||||
两层独立叠加,互不替代:
|
||||
|
||||
两者可以同时生效,租户隔离优先级更高。
|
||||
```text
|
||||
Scope 注入顺序:软删 del_flag=0 → 租户 tenant_id 条件 →(applyFilters 链)→ 数据范围
|
||||
```
|
||||
|
||||
租户隔离保证"看不到别的租户",数据权限保证"本租户内按部门/本人收敛"。
|
||||
|
||||
## 配置与调试
|
||||
|
||||
- 档位在角色管理界面设置
|
||||
- 调试时可对比同一接口以不同角色调用的结果集差异
|
||||
- 超管(平台级)不受数据权限约束,用于管理与稽核
|
||||
|
||||
## 下一步
|
||||
|
||||
→ [5.11 字典模块](/zh/core/dict.html)
|
||||
|
||||
Reference in New Issue
Block a user