feat: add tenant-scoped rule and permission management
This commit is contained in:
@@ -0,0 +1,709 @@
|
||||
# 统一数据范围执行器设计
|
||||
|
||||
> 适用范围:`leaudit-platform` 当前 `RBAC + 单地区隔离 + 模块特例策略` 体系
|
||||
> 文档定位:把“data_scope 已建模但未统一执行”的现状,收敛为一套后端可落地的统一执行器设计。
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计结论
|
||||
|
||||
当前系统真正缺的不是权限表,也不是权限点,而是一个统一的“数据范围执行层”。
|
||||
|
||||
现状已经具备:
|
||||
|
||||
- `roles.data_scope`
|
||||
- `role_permissions.data_scope`
|
||||
- `role_permissions.grant_type = GRANT / DENY`
|
||||
- 用户主地区 `sso_users.area`
|
||||
- 多个模块已存在真实可运行的数据边界实现
|
||||
|
||||
当前系统真正缺失的是:
|
||||
|
||||
1. 平台层没有把“功能权限 + 数据范围 + 模块特例策略”合并成一次统一决策
|
||||
2. `PermissionServiceImpl` 只返回布尔值,不返回 scope 决策
|
||||
3. 文档、公文、统计、合同模板、RBAC 管理域都在各自重复写 `is_global/can_manage/area/created_by`
|
||||
4. RAG、交叉评查等特殊模块没有被纳入统一决策框架,只能继续靠模块内手工判断
|
||||
|
||||
因此,建议新增统一执行链:
|
||||
|
||||
1. `PermissionDecisionService`
|
||||
2. `DataScopeResolver`
|
||||
3. `QueryScopeBuilder`
|
||||
4. `ModulePolicyRegistry`
|
||||
5. `ScopeAwarePermissionFacade`
|
||||
|
||||
目标不是推翻当前业务 SQL,而是先把“决策入口”和“范围解释逻辑”统一,再逐模块替换已有散落实现。
|
||||
|
||||
---
|
||||
|
||||
## 2. 统一执行器要解决什么问题
|
||||
|
||||
## 2.1 功能准入和数据范围必须拆开
|
||||
|
||||
一个接口是否可调用,与一个用户调用后能看到多少数据,是两层不同问题:
|
||||
|
||||
- 功能准入:是否拥有 `permission_key`
|
||||
- 数据范围:即便拥有该权限,可见范围到底是 `ALL / DEPT / SELF / RELATION / PUBLIC_MIXED`
|
||||
|
||||
当前系统多数地方只做了第一层,第二层分散在 service 内。
|
||||
|
||||
## 2.2 多角色用户必须有统一合并规则
|
||||
|
||||
当前库允许一个用户绑定多个角色:
|
||||
|
||||
- 一个角色可能 `GRANT documents:list:read + SELF`
|
||||
- 另一个角色可能 `GRANT documents:list:read + DEPT`
|
||||
- 还有角色可能 `DENY documents:list:read`
|
||||
|
||||
没有统一合并规则,就会出现:
|
||||
|
||||
- 有人按最大范围放行
|
||||
- 有人按主角色放行
|
||||
- 有人忽略 `DENY`
|
||||
|
||||
## 2.3 模块差异必须被显式建模
|
||||
|
||||
不是所有模块都适合硬套 `ALL/DEPT/SELF`:
|
||||
|
||||
- 文档、公文、统计:典型数据范围模型
|
||||
- RAG:`地区 + 公开(public)` 混合模型
|
||||
- 交叉评查:任务成员关系模型
|
||||
- 规则/配置域:更偏功能权限域
|
||||
|
||||
所以统一执行器不能只有一个“拼 where region = ?”函数,而要允许模块策略扩展。
|
||||
|
||||
---
|
||||
|
||||
## 3. 总体架构
|
||||
|
||||
建议新增如下能力层。
|
||||
|
||||
## 3.1 核心对象
|
||||
|
||||
### 3.1.1 `ScopeContext`
|
||||
|
||||
表示一次权限决策的输入上下文。
|
||||
|
||||
建议字段:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ScopeContext:
|
||||
user_id: int
|
||||
permission_key: str
|
||||
module: str
|
||||
action: str
|
||||
user_area: str | None
|
||||
request_area: str | None = None
|
||||
target_user_id: int | None = None
|
||||
resource_id: int | None = None
|
||||
extra_filters: dict[str, Any] | None = None
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `user_area` 来自 `sso_users.area`
|
||||
- `request_area` 是接口显式传入的筛选地区
|
||||
- `target_user_id` 适用于按用户过滤的查询
|
||||
- `resource_id` 适用于详情、删除、下载这类单资源接口
|
||||
- `extra_filters` 给统计、RAG、交叉评查等模块挂业务参数
|
||||
|
||||
### 3.1.2 `PermissionGrant`
|
||||
|
||||
表示从数据库查出的单条授权记录。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class PermissionGrant:
|
||||
role_id: int
|
||||
role_key: str
|
||||
permission_key: str
|
||||
grant_type: str
|
||||
role_scope: str | None
|
||||
permission_scope: str | None
|
||||
condition_filter: dict[str, Any] | None
|
||||
priority: int
|
||||
is_system_role: bool
|
||||
```
|
||||
|
||||
### 3.1.3 `PermissionDecision`
|
||||
|
||||
表示平台最终产出的权限决策。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class PermissionDecision:
|
||||
allowed: bool
|
||||
deny_reason: str | None
|
||||
effective_scope: str | None
|
||||
scope_mode: str
|
||||
allowed_areas: list[str]
|
||||
allowed_user_ids: list[int]
|
||||
allow_public: bool
|
||||
conditions: dict[str, Any]
|
||||
matched_roles: list[str]
|
||||
matched_permissions: list[str]
|
||||
```
|
||||
|
||||
建议 `scope_mode` 取值:
|
||||
|
||||
- `NONE`:不做数据范围控制
|
||||
- `ALL`
|
||||
- `DEPT`
|
||||
- `SELF`
|
||||
- `RELATION`
|
||||
- `PUBLIC_MIXED`
|
||||
- `CUSTOM`
|
||||
|
||||
### 3.1.4 `ScopeClause`
|
||||
|
||||
表示最终用于拼接 SQL 的范围子句。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ScopeClause:
|
||||
sql: str
|
||||
params: dict[str, Any]
|
||||
scope_mode: str
|
||||
description: str
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 执行链路
|
||||
|
||||
建议所有需要“权限 + 数据边界”的 service 统一走下面链路:
|
||||
|
||||
```text
|
||||
Controller
|
||||
-> ScopeAwarePermissionFacade.require()
|
||||
-> PermissionDecisionService.decide()
|
||||
-> PermissionGrantRepository.load_user_grants()
|
||||
-> DataScopeResolver.resolve()
|
||||
-> ModulePolicyRegistry.get(module).decorate()
|
||||
-> QueryScopeBuilder.build()
|
||||
-> Service 执行业务 SQL / ORM
|
||||
```
|
||||
|
||||
细化如下:
|
||||
|
||||
1. 控制器或 service 构造 `ScopeContext`
|
||||
2. `PermissionDecisionService` 先确认该用户是否拥有功能权限
|
||||
3. 若被 `DENY` 命中,直接拒绝
|
||||
4. 若 `GRANT` 命中,则计算有效范围
|
||||
5. 若模块存在特例策略,由 `ModulePolicy` 二次修饰决策
|
||||
6. 由 `QueryScopeBuilder` 将决策转换为统一 SQL 子句
|
||||
7. 业务 service 只负责把子句注入原查询,不再自行解释角色
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据来源与优先级规则
|
||||
|
||||
## 5.1 数据来源
|
||||
|
||||
统一执行器的决策数据来自 4 层:
|
||||
|
||||
1. `sso_users.area`
|
||||
2. `roles.data_scope`
|
||||
3. `role_permissions.data_scope`
|
||||
4. `role_permissions.grant_type / condition_filter`
|
||||
|
||||
## 5.2 功能准入优先级
|
||||
|
||||
功能准入保持现有语义,但要扩展为“带授权明细返回”:
|
||||
|
||||
1. 精确 `DENY`
|
||||
2. 通配符 `DENY`
|
||||
3. 精确 `GRANT`
|
||||
4. 通配符 `GRANT`
|
||||
5. 无匹配则拒绝
|
||||
|
||||
这部分沿用 `PermissionServiceImpl` 现有规则,不改语义。
|
||||
|
||||
## 5.3 范围优先级
|
||||
|
||||
建议统一采用:
|
||||
|
||||
1. `role_permissions.data_scope`
|
||||
2. `roles.data_scope`
|
||||
3. 模块默认值
|
||||
|
||||
即:
|
||||
|
||||
- 权限级 scope 覆盖角色级 scope
|
||||
- 角色级 scope 覆盖模块默认值
|
||||
- 若都没有,读接口默认 `SELF`,配置接口默认 `NONE`
|
||||
|
||||
## 5.4 多角色合并规则
|
||||
|
||||
建议采用:
|
||||
|
||||
1. 先按 `DENY` 决定是否整体拒绝
|
||||
2. 在所有有效 `GRANT` 中取“最大可见范围”
|
||||
3. 若存在模块策略,则再由模块策略收敛边界
|
||||
|
||||
范围大小建议定义为:
|
||||
|
||||
```text
|
||||
ALL > DEPT > SELF
|
||||
GROUP 不再扩展,仅兼容映射
|
||||
RELATION / PUBLIC_MIXED / CUSTOM 由模块策略生成
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- `DENY` 是功能拒绝,不只是 scope 收缩
|
||||
- 不能把一个 `DENY documents:list:read` 理解成“降到 SELF”
|
||||
- 一旦该权限被 `DENY` 命中,应直接 `allowed = False`
|
||||
|
||||
## 5.5 `GROUP` 的处理
|
||||
|
||||
库里仍保留 `GROUP`,但当前系统没有成熟“组织组”模型。
|
||||
|
||||
建议:
|
||||
|
||||
- 现阶段统一映射为 `DEPT`
|
||||
- 文档和代码中明确标注“仅兼容,不新增使用”
|
||||
- 后续如果真要启用组织组,再单独扩展
|
||||
|
||||
---
|
||||
|
||||
## 6. 范围语义规范
|
||||
|
||||
## 6.1 `ALL`
|
||||
|
||||
含义:
|
||||
|
||||
- 可见该模块全部数据
|
||||
- 可按任意地区或任意用户进一步筛选
|
||||
|
||||
适用:
|
||||
|
||||
- 省级管理员
|
||||
- 超级管理员
|
||||
- 某些总部配置权限
|
||||
|
||||
## 6.2 `DEPT`
|
||||
|
||||
本项目中 `DEPT` 语义应明确定义为:
|
||||
|
||||
- 同主地区 `area`
|
||||
|
||||
不是传统部门树。
|
||||
|
||||
含义:
|
||||
|
||||
- 只能看与自身 `user_area` 相同地区的数据
|
||||
- 如接口显式传入 `request_area`,则必须等于 `user_area`
|
||||
|
||||
## 6.3 `SELF`
|
||||
|
||||
含义:
|
||||
|
||||
- 仅可看与自己直接归属的数据
|
||||
|
||||
优先字段通常是:
|
||||
|
||||
- `created_by`
|
||||
- `owner_id`
|
||||
- `user_id`
|
||||
|
||||
必须按模块字段映射规范执行,不能每个模块再自行猜测。
|
||||
|
||||
## 6.4 `RELATION`
|
||||
|
||||
适用于交叉评查等成员关系模型。
|
||||
|
||||
含义:
|
||||
|
||||
- 可访问与当前用户存在显式关系绑定的数据
|
||||
|
||||
例如:
|
||||
|
||||
- `task_member.user_id = current_user_id`
|
||||
- `proposal.created_by = current_user_id`
|
||||
- `document` 属于当前参与任务
|
||||
|
||||
## 6.5 `PUBLIC_MIXED`
|
||||
|
||||
适用于 RAG。
|
||||
|
||||
含义:
|
||||
|
||||
- 本地区资源可见
|
||||
- 公共资源可见
|
||||
- 省级公共资源可见
|
||||
|
||||
本质条件通常是:
|
||||
|
||||
```sql
|
||||
resource.area IN (:user_area, '省级', '')
|
||||
OR resource.is_public = TRUE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 通用字段映射规范
|
||||
|
||||
统一执行器要避免“模块自己猜字段名”,必须先定义字段映射表。
|
||||
|
||||
## 7.1 推荐映射对象
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ScopeFieldMapping:
|
||||
area_field: str | None = None
|
||||
creator_field: str | None = None
|
||||
owner_field: str | None = None
|
||||
user_field: str | None = None
|
||||
```
|
||||
|
||||
## 7.2 模块字段规范
|
||||
|
||||
### 文档模块
|
||||
|
||||
- area 字段:`d.region`
|
||||
- self 字段:`f.created_by` 或主文档归属用户
|
||||
|
||||
说明:
|
||||
|
||||
- 当前文档真实归属更多落在文件记录 `created_by`
|
||||
- 统一接入时要固定“列表/详情/附件/结果”的归属判断口径
|
||||
|
||||
### 公文模块
|
||||
|
||||
- area 字段:`d.region`
|
||||
- self 字段:`f.created_by`
|
||||
|
||||
### 使用统计模块
|
||||
|
||||
按口径不同分两类:
|
||||
|
||||
- 用户口径 area:`u.area`
|
||||
- 文档口径 area:`d.region`
|
||||
- self 字段:`f.created_by` 或 `u.id`
|
||||
|
||||
### 合同模板模块
|
||||
|
||||
- area 字段:`t.region`
|
||||
- self 字段:`t.created_by`
|
||||
|
||||
### RBAC 用户管理
|
||||
|
||||
- area 字段:`u.area`
|
||||
- self 字段:通常不用
|
||||
|
||||
### RAG 数据集/应用
|
||||
|
||||
- area 字段:`dataset.area` / `app.area`
|
||||
- self 字段:按创建者字段补充
|
||||
- public 字段:`is_public`
|
||||
|
||||
### 交叉评查
|
||||
|
||||
- 不优先走 `area_field`
|
||||
- 主入口走关系字段:
|
||||
- `task_member.user_id`
|
||||
- `proposal.created_by`
|
||||
- `vote.user_id`
|
||||
|
||||
---
|
||||
|
||||
## 8. 模块策略设计
|
||||
|
||||
统一执行器不能只靠 `ALL/DEPT/SELF`,必须允许模块策略。
|
||||
|
||||
## 8.1 `ModulePolicy` 接口
|
||||
|
||||
```python
|
||||
class ModulePolicy(Protocol):
|
||||
def decorate(self, ctx: ScopeContext, decision: PermissionDecision) -> PermissionDecision: ...
|
||||
def build_clause(self, ctx: ScopeContext, decision: PermissionDecision) -> ScopeClause | None: ...
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `decorate()` 负责把通用 scope 转成模块实际策略
|
||||
- `build_clause()` 负责拼接模块专属条件
|
||||
|
||||
## 8.2 DocumentPolicy
|
||||
|
||||
适用模块:
|
||||
|
||||
- 文档列表
|
||||
- 文档详情
|
||||
- 文档状态
|
||||
- 评查点聚合
|
||||
- 附件追加
|
||||
- 文档确认
|
||||
|
||||
建议策略:
|
||||
|
||||
- `ALL`:不加地区限制,但允许 `request_area`
|
||||
- `DEPT`:固定 `d.region = user_area`
|
||||
- `SELF`:固定 `f.created_by = current_user_id`
|
||||
- 单资源接口必须先验证资源是否在 scope 内,再做更新/删除
|
||||
|
||||
## 8.3 GovdocPolicy
|
||||
|
||||
建议策略:
|
||||
|
||||
- 与文档模块同一套 area/self 语义
|
||||
- `run/result/report/download` 等派生接口必须继承 document scope
|
||||
- 不能只校验 `run_id` 是否存在,必须回溯到所属 `document_id`
|
||||
|
||||
## 8.4 UsageStatsPolicy
|
||||
|
||||
建议策略:
|
||||
|
||||
- `overview/trends/by-areas`:支持 `ALL/DEPT`
|
||||
- `by-users/by-departments/details`:支持 `ALL/DEPT/SELF`
|
||||
- `SELF` 时只允许看到自己的登录、上传、评查明细
|
||||
- `areaScope=document` 与 `areaScope=user` 由模块策略切换字段映射
|
||||
|
||||
## 8.5 RagPolicy
|
||||
|
||||
建议策略:
|
||||
|
||||
- 读取类接口:`PUBLIC_MIXED`
|
||||
- 管理类接口:`ALL/DEPT/SELF` + 资源属地校验
|
||||
|
||||
拆分为两类:
|
||||
|
||||
1. `rag:app:read` / `rag:chat:use` / `rag:dataset:read`
|
||||
- 允许 `本地区 + 省级 + 公共`
|
||||
2. `rag:dataset:manage/create/update/delete`
|
||||
- 不再按 `UserRole` 白名单
|
||||
- 统一按 `permission + scope` 决定
|
||||
|
||||
## 8.6 CrossReviewPolicy
|
||||
|
||||
建议策略:
|
||||
|
||||
- 主模型使用 `RELATION`
|
||||
- `task:read` 不是 area 过滤,而是成员关系过滤
|
||||
- `document:complete` 不是角色白名单,而是“拥有权限 + 是任务参与者/负责方”
|
||||
- `proposal:read/export` 必须通过文档所属任务关系回溯校验
|
||||
|
||||
结论:
|
||||
|
||||
- 交叉评查接入统一执行器
|
||||
- 但不强制落到普通 `ALL/DEPT/SELF`
|
||||
- 它是统一框架下的特例策略,不是例外代码
|
||||
|
||||
## 8.7 RbacAdminPolicy
|
||||
|
||||
建议策略:
|
||||
|
||||
- 角色、用户、组织树、路由、授权查询等接口优先按 `u.area`
|
||||
- 全局管理员看全部
|
||||
- 地区管理员仅管理本地区用户
|
||||
- 角色对象本身通常不按地区分表,但“角色绑定到哪些用户”仍受用户 area 边界约束
|
||||
|
||||
---
|
||||
|
||||
## 9. QueryScopeBuilder 设计
|
||||
|
||||
## 9.1 目标
|
||||
|
||||
把 `PermissionDecision` 转成业务可注入的条件,而不是让业务自己重新解释。
|
||||
|
||||
## 9.2 建议接口
|
||||
|
||||
```python
|
||||
class QueryScopeBuilder:
|
||||
def build_by_mapping(
|
||||
self,
|
||||
decision: PermissionDecision,
|
||||
mapping: ScopeFieldMapping,
|
||||
current_user_id: int,
|
||||
user_area: str | None,
|
||||
request_area: str | None = None,
|
||||
) -> ScopeClause: ...
|
||||
```
|
||||
|
||||
## 9.3 通用构造规则
|
||||
|
||||
### `ALL`
|
||||
|
||||
```sql
|
||||
1 = 1
|
||||
```
|
||||
|
||||
若带 `request_area`:
|
||||
|
||||
```sql
|
||||
COALESCE(area_field, '') = :request_area
|
||||
```
|
||||
|
||||
### `DEPT`
|
||||
|
||||
```sql
|
||||
COALESCE(area_field, '') = :scope_area
|
||||
```
|
||||
|
||||
并且:
|
||||
|
||||
- 若 `request_area` 非空且不等于 `user_area`,直接拒绝
|
||||
|
||||
### `SELF`
|
||||
|
||||
优先级:
|
||||
|
||||
1. `creator_field`
|
||||
2. `owner_field`
|
||||
3. `user_field`
|
||||
|
||||
生成:
|
||||
|
||||
```sql
|
||||
creator_field = :current_user_id
|
||||
```
|
||||
|
||||
### `PUBLIC_MIXED`
|
||||
|
||||
```sql
|
||||
(
|
||||
COALESCE(area_field, '') IN :visible_areas
|
||||
OR public_field = TRUE
|
||||
)
|
||||
```
|
||||
|
||||
### `RELATION`
|
||||
|
||||
由模块策略返回完整 SQL 子句,不走通用拼接。
|
||||
|
||||
---
|
||||
|
||||
## 10. 权限决策缓存建议
|
||||
|
||||
当前 `PermissionServiceImpl` 已有 60 秒权限集合缓存。
|
||||
|
||||
建议统一执行器增加两层缓存:
|
||||
|
||||
1. 用户授权明细缓存
|
||||
2. 用户能力快照缓存
|
||||
|
||||
建议缓存内容:
|
||||
|
||||
- grant / deny 结果
|
||||
- 每个 `permission_key` 对应的有效 scope
|
||||
- 用户 `area`
|
||||
- 用户角色列表
|
||||
|
||||
注意:
|
||||
|
||||
- 缓存里只存决策原料,不缓存最终 SQL
|
||||
- 角色变更、权限变更、用户地区变更后,应主动失效
|
||||
|
||||
---
|
||||
|
||||
## 11. 建议代码落点
|
||||
|
||||
建议新增目录:
|
||||
|
||||
```text
|
||||
fastapi_modules/fastapi_leaudit/services/permission_scope/
|
||||
decision_models.py
|
||||
permissionDecisionService.py
|
||||
dataScopeResolver.py
|
||||
queryScopeBuilder.py
|
||||
modulePolicies/
|
||||
base.py
|
||||
documentPolicy.py
|
||||
govdocPolicy.py
|
||||
usageStatsPolicy.py
|
||||
ragPolicy.py
|
||||
crossReviewPolicy.py
|
||||
rbacAdminPolicy.py
|
||||
```
|
||||
|
||||
建议改造现有:
|
||||
|
||||
- `services/impl/permissionServiceImpl.py`
|
||||
- 保留布尔接口
|
||||
- 新增返回授权明细的方法
|
||||
- `services/permissionService.py`
|
||||
- 增加 `GetPermissionDecision`
|
||||
- `services/impl/documentServiceImpl.py`
|
||||
- `services/impl/govdocServiceImpl.py`
|
||||
- `services/impl/usageStatsServiceImpl.py`
|
||||
- `services/impl/ragDatasetServiceImpl.py`
|
||||
- `services/impl/ragChatServiceImpl.py`
|
||||
- `services/impl/rbacAdminServiceImpl.py`
|
||||
- `services/impl/contractTemplateServiceImpl.py`
|
||||
|
||||
---
|
||||
|
||||
## 12. 推荐接入顺序
|
||||
|
||||
## 12.1 第一批
|
||||
|
||||
- RAG
|
||||
- 文档
|
||||
- 公文
|
||||
- 使用统计
|
||||
|
||||
原因:
|
||||
|
||||
- 这几块最明显存在范围逻辑分散或双轨冲突
|
||||
- 风险最高,收益也最大
|
||||
|
||||
## 12.2 第二批
|
||||
|
||||
- RBAC 管理域
|
||||
- 合同模板
|
||||
- 首页入口模块
|
||||
|
||||
## 12.3 第三批
|
||||
|
||||
- 交叉评查接入统一决策框架
|
||||
- 前端联动改为只认权限与服务端返回能力
|
||||
|
||||
---
|
||||
|
||||
## 13. 与现有代码的映射关系
|
||||
|
||||
当前散落逻辑,建议按下述替换:
|
||||
|
||||
- `documentServiceImpl._getCurrentUserContext`
|
||||
- 替换为 `PermissionDecisionService + ScopeContext`
|
||||
- `documentServiceImpl._buildDocumentScopeFilters`
|
||||
- 替换为 `QueryScopeBuilder + DocumentPolicy`
|
||||
- `govdocServiceImpl` 内 area/created_by 过滤
|
||||
- 替换为 `GovdocPolicy`
|
||||
- `usageStatsServiceImpl._build_user_scope_condition`
|
||||
- 替换为 `UsageStatsPolicy`
|
||||
- `contractTemplateServiceImpl` 内 `is_global/can_manage`
|
||||
- 替换为 `ScopeDecision`
|
||||
- `rbacAdminServiceImpl` 内 `bool_or(role_key IN (...))`
|
||||
- 替换为统一管理域能力决策
|
||||
- `ragDatasetServiceImpl` / `ragChatServiceImpl` 内 `UserRole` 白名单
|
||||
- 替换为 `RagPolicy`
|
||||
|
||||
---
|
||||
|
||||
## 14. 验收标准
|
||||
|
||||
统一执行器设计落地后,应满足以下标准:
|
||||
|
||||
1. 新增一个 permission 时,可以同时配置 data_scope,并被平台自动执行
|
||||
2. 文档、公文、统计、RAG 不再自行硬编码角色解释范围
|
||||
3. `DENY`、多角色合并、地区限制有统一规则
|
||||
4. 详情、删除、下载、导出接口与列表接口共享同一 scope 决策
|
||||
5. 前端不再需要猜测“省级管理员/市级管理员能看到哪些数据”
|
||||
|
||||
---
|
||||
|
||||
## 15. 最终建议
|
||||
|
||||
这次改造不应该继续扩写更多 `is_global/can_manage` 工具函数,而应直接建立统一执行器。
|
||||
|
||||
如果继续在各 service 内复制现有模式,后续问题会持续扩大:
|
||||
|
||||
- 数据范围无法统一验收
|
||||
- 新角色接入成本持续上升
|
||||
- 前后端边界会长期不一致
|
||||
- RAG、交叉评查这类特例模块会越来越难治理
|
||||
|
||||
统一数据范围执行器是本轮权限架构改造的核心平台能力,优先级应为最高。
|
||||
Reference in New Issue
Block a user