签入版本
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# 5.9 数据权限
|
||||
|
||||
:::tip 概述
|
||||
数据权限控制用户能看到哪些数据,基于角色的 `data_scope` 字段进行过滤。支持三种范围:全部数据、本部门数据、仅本人数据。
|
||||
数据权限控制用户能看到哪些数据,由 `HasDataScope` Trait 的 `applyDataScope()` 在查询构建时按角色数据范围自动叠加过滤条件,支持三种范围:全部数据、本部门数据、仅本人数据。当前 `laravel_role` 表不含 `data_scope` 字段——`getRoleDataScope()` 读取缺省为 1,所有角色按全部数据处理。
|
||||
:::
|
||||
|
||||
## 三种范围
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ data_scope = 3 │
|
||||
│ 仅本人数据 │
|
||||
│ 仅本人数据(无角色用户默认) │
|
||||
│ │
|
||||
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
|
||||
│ │ A │ │ B │ │███│ │ D │ │ E │ ← 只看到自己创建的数据 │
|
||||
@@ -37,23 +37,25 @@
|
||||
|
||||
## 配置方式
|
||||
|
||||
在 Logic 中配置数据权限字段即可启用:
|
||||
:::warning 前置条件
|
||||
数据权限能力由 `HasDataScope` Trait 提供——继承 `BaseTenantService` 的服务已自动 `use` 该 Trait;直接继承 `BaseService` 的服务需自行 `use Concerns\HasDataScope`。且 **`BaseTenantService` 默认未启用数据权限**,子类必须声明字段才会生效。
|
||||
:::
|
||||
|
||||
```php
|
||||
class UserLogic extends BaseTenantLogic
|
||||
class UserService extends BaseTenantService
|
||||
{
|
||||
/**
|
||||
* 数据权限:部门关联字段名(用于按部门过滤)
|
||||
* 数据权限:部门关联字段名(用于按部门过滤,data_scope=2 时生效)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $dataScopeDeptField = 'dept_id';
|
||||
}
|
||||
|
||||
class ArticleLogic extends BaseTenantLogic
|
||||
class ArticleService extends BaseTenantService
|
||||
{
|
||||
/**
|
||||
* 数据权限:归属字段名(用于按创建人过滤)
|
||||
* 数据权限:归属字段名(用于按创建人过滤,data_scope=3 时生效)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
@@ -61,72 +63,95 @@ class ArticleLogic extends BaseTenantLogic
|
||||
}
|
||||
```
|
||||
|
||||
| 属性 | 生效场景 | 过滤条件 |
|
||||
|------|---------|---------|
|
||||
| `dataScopeDeptField` | `data_scope=2` 本部门 | `WHERE {字段} = 当前用户部门ID` |
|
||||
| `dataScopeUserField` | `data_scope=3` 仅本人 | `WHERE {字段} = 当前用户名` |
|
||||
|
||||
## 实现机制
|
||||
|
||||
```php
|
||||
// app/BaseLogic.php
|
||||
// app/Services/Concerns/HasDataScope.php(行为说明)
|
||||
|
||||
protected function applyDataScope($model)
|
||||
protected function applyDataScope($query)
|
||||
{
|
||||
// 未配置数据权限字段则跳过
|
||||
if (empty($this->dataScopeUserField) && empty($this->dataScopeDeptField)) {
|
||||
return $model;
|
||||
return $query;
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
$userInfo = request()->userInfo ?? null;
|
||||
$uid = $userInfo->uid ?? 0;
|
||||
$roleId = $userInfo->role_id ?? 0;
|
||||
|
||||
// 获取角色的数据权限范围
|
||||
$dataScope = $this->getRoleDataScope($roleId);
|
||||
|
||||
// 1=全部数据,不做过滤
|
||||
if ($dataScope == 1) {
|
||||
return $model;
|
||||
return $query;
|
||||
}
|
||||
|
||||
// 2=本部门数据
|
||||
// 2=本部门数据(配置了 dataScopeDeptField 时)
|
||||
if ($dataScope == 2 && $this->dataScopeDeptField) {
|
||||
$deptId = $this->getUserDeptId($uid);
|
||||
if ($deptId) {
|
||||
$model = $model->where($this->dataScopeDeptField, $deptId);
|
||||
$query = $query->where($this->dataScopeDeptField, $deptId);
|
||||
}
|
||||
return $model;
|
||||
return $query;
|
||||
}
|
||||
|
||||
// 3=仅本人数据
|
||||
// 3=仅本人数据(配置了 dataScopeUserField 时)
|
||||
if ($dataScope == 3 && $this->dataScopeUserField) {
|
||||
$model = $model->where($this->dataScopeUserField, $userInfo->username);
|
||||
return $model;
|
||||
return $query->where($this->dataScopeUserField, $username);
|
||||
}
|
||||
|
||||
return $model;
|
||||
return $query;
|
||||
}
|
||||
```
|
||||
|
||||
## 角色配置
|
||||
**查询链中的位置**(`HasQueryScopes::buildQuery`):
|
||||
|
||||
在角色管理中设置 `data_scope` 字段:
|
||||
```text
|
||||
额外固定条件($where)
|
||||
→ LIKE 模糊匹配(pageLikeFields)
|
||||
→ 精确匹配(pageEqFields)
|
||||
→ 数据权限过滤(applyDataScope) ← 本节
|
||||
→ 租户隔离过滤(applyTenantScope)
|
||||
```
|
||||
|
||||
:::warning 无角色用户
|
||||
无角色时默认按"仅本人"(scope=3)处理——宁可少看,不可多看。
|
||||
:::
|
||||
|
||||
## 数据范围语义
|
||||
|
||||
`getRoleDataScope()` 按以下范围解析(`HasDataScope` 内部实现):
|
||||
|
||||
| 值 | 范围 | 适用场景 |
|
||||
|----|------|----------|
|
||||
| 1 | 全部数据 | 管理层、超级管理员 |
|
||||
| 1 | 全部数据 | 管理层、超级管理员(当前默认) |
|
||||
| 2 | 本部门数据 | 部门经理 |
|
||||
| 3 | 仅本人数据 | 普通员工 |
|
||||
| 3 | 仅本人数据 | 普通员工(无角色用户默认) |
|
||||
|
||||
## 缓存说明
|
||||
|
||||
角色的数据权限范围带 1 小时缓存(`role_data_scope_{roleId}`)。修改角色权限后需等待缓存过期或手动清除。
|
||||
:::info 当前版本现状
|
||||
`laravel_role` 表不包含 `data_scope` 字段(按当前表设计),角色一律解析为 1(全部数据);上表为 `HasDataScope` 的完整语义。服务只需声明 `dataScopeUserField` / `dataScopeDeptField` 字段,范围解析逻辑保持不变。
|
||||
:::
|
||||
|
||||
## 超级管理员
|
||||
|
||||
`uid=1` 的超级管理员不受数据权限限制,始终看到全部数据。详见 [RBAC 权限管理](/zh/core/rbac.html)。
|
||||
`uid=1` 的超级管理员不受数据权限限制(权限与租户校验均跳过),始终看到全部数据。详见 [5.4 权限管理(RBAC)](/zh/core/rbac.html)。
|
||||
|
||||
## 与租户隔离的关系
|
||||
|
||||
数据权限和租户隔离是两个独立的维度:
|
||||
- **租户隔离**:按 `tenant_id` 过滤,不同租户数据完全隔离
|
||||
- **数据权限**:在同一租户内,按部门或创建人进一步过滤
|
||||
|
||||
两者可以同时生效,租户隔离优先级更高。
|
||||
- **租户隔离**:按 `tenant_id` 过滤,不同租户数据完全隔离(`BaseTenantService` 自动启用)
|
||||
- **数据权限**:在同一租户内,按部门或创建人进一步过滤(需声明字段启用)
|
||||
|
||||
两者可以同时生效,租户隔离优先级更高(先租户、后数据权限)。详见 [5.8 多租户隔离](/zh/core/tenant.html)。
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 现象 | 原因 | 处理 |
|
||||
|------|------|------|
|
||||
| 配置了字段但过滤不生效 | 服务未启用 `HasDataScope` | 继承 `BaseTenantService` 或手动 `use` Trait |
|
||||
| 普通用户看到全部数据 | 当前角色数据范围解析为 1(表无 `data_scope` 字段) | 属于当前版本现状,见上文「数据范围语义」 |
|
||||
| 部门过滤失效(scope=2) | 未配置 `dataScopeDeptField` 或用户无部门 | 声明字段并给用户分配部门 |
|
||||
| 仅本人过滤失效(scope=3) | 未配置 `dataScopeUserField` | 声明字段(如 `create_user`) |
|
||||
|
||||
Reference in New Issue
Block a user