feat: add tenant-scoped rule and permission management
This commit is contained in:
@@ -0,0 +1,830 @@
|
||||
# 权限字段映射与 SQL 改造规范
|
||||
|
||||
> 适用范围:`leaudit-platform` 后端权限改造中的查询语句、资源详情、导出下载、统计聚合、管理列表
|
||||
> 文档定位:为统一数据范围执行器的接入提供字段映射标准、SQL 拼接规范、资源回溯规范和反模式约束。
|
||||
|
||||
---
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
这份文档解决的是一个非常具体的问题:
|
||||
|
||||
统一数据范围执行器设计出来以后,后端各模块到底怎么把它安全、稳定地接到现有 SQL 上。
|
||||
|
||||
当前项目最大风险不是“不会写 scope”,而是:
|
||||
|
||||
1. 同一个模块里不同查询使用了不同字段口径
|
||||
2. 列表、详情、下载、导出没有复用同一主资源边界
|
||||
3. 各 service 自己拼 `1 = 0`、`region`、`created_by`,可维护性很差
|
||||
4. 多表 join 时,究竟该按 `u.area` 还是 `d.region`,目前没有统一规范
|
||||
|
||||
所以这份文档的目标是:
|
||||
|
||||
1. 定义统一字段映射标准
|
||||
2. 定义统一 alias 规范
|
||||
3. 定义统一 scope 子句拼接方式
|
||||
4. 定义详情、下载、导出等派生资源的“主资源回溯”规则
|
||||
5. 定义改造时哪些 SQL 能保留,哪些必须重构
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前代码里已经暴露出的典型问题
|
||||
|
||||
结合现有实现,已经确认有以下模式:
|
||||
|
||||
- `documentServiceImpl` / `govdocServiceImpl`
|
||||
- 通过 `d.region` + `f.created_by` 控制范围
|
||||
- `usageStatsServiceImpl`
|
||||
- 有时按 `u.area`
|
||||
- 有时按 `d.region`
|
||||
- 有时还要按 `e.area_snapshot`
|
||||
- `contractTemplateServiceImpl`
|
||||
- 既有 `t.region`
|
||||
- 又有 `t.created_by`
|
||||
- 还混入“省级模板可见”
|
||||
- `rbacAdminServiceImpl`
|
||||
- 用户列表、组织树本质上按 `u.area`
|
||||
|
||||
这说明项目不是“没有规则”,而是规则散了。
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心原则
|
||||
|
||||
## 3.1 先确定主资源,再确定 scope 字段
|
||||
|
||||
SQL 改造第一步不是拼条件,而是先回答:
|
||||
|
||||
- 这个接口的主资源是谁?
|
||||
|
||||
例如:
|
||||
|
||||
- 文档列表:主资源是 `document`
|
||||
- 文档状态:主资源仍是 `document`
|
||||
- 公文报告下载:主资源不是 `report_artifact`,而是 `govdoc document`
|
||||
- RAG 文档分段列表:主资源不是 `segment`,而是 `dataset`
|
||||
- 交叉评查提案导出:主资源不是 `proposal`,而是“用户参与的任务文档”
|
||||
|
||||
只有先确定主资源,scope 才不会跑偏。
|
||||
|
||||
## 3.2 范围条件必须挂在主资源口径上
|
||||
|
||||
同一个接口里如果出现多表:
|
||||
|
||||
- `document d`
|
||||
- `document_file f`
|
||||
- `sso_users u`
|
||||
|
||||
必须先规定:
|
||||
|
||||
- area 看哪个表
|
||||
- self 看哪个表
|
||||
|
||||
不能在同一个模块里一会儿 `u.area`,一会儿 `d.region`,又没有解释。
|
||||
|
||||
## 3.3 列表、详情、删除、下载、导出必须继承同一套 scope
|
||||
|
||||
这条必须强制执行。
|
||||
|
||||
不允许出现:
|
||||
|
||||
- 列表按文档范围过滤
|
||||
- 详情直接按 `id`
|
||||
- 下载直接按附件 `id`
|
||||
- 导出直接按 run `id`
|
||||
|
||||
凡是派生资源,都必须回溯主资源。
|
||||
|
||||
---
|
||||
|
||||
## 4. 统一字段映射标准
|
||||
|
||||
## 4.1 标准字段分类
|
||||
|
||||
建议统一按 5 类字段管理:
|
||||
|
||||
1. `area_field`
|
||||
2. `creator_field`
|
||||
3. `owner_field`
|
||||
4. `user_field`
|
||||
5. `public_field`
|
||||
|
||||
建议结构:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ScopeFieldMapping:
|
||||
area_field: str | None = None
|
||||
creator_field: str | None = None
|
||||
owner_field: str | None = None
|
||||
user_field: str | None = None
|
||||
public_field: str | None = None
|
||||
```
|
||||
|
||||
## 4.2 字段语义定义
|
||||
|
||||
### `area_field`
|
||||
|
||||
表示资源的地区归属字段。
|
||||
|
||||
例如:
|
||||
|
||||
- `d.region`
|
||||
- `t.region`
|
||||
- `dataset.area`
|
||||
- `app.area`
|
||||
- `u.area`
|
||||
|
||||
### `creator_field`
|
||||
|
||||
表示“创建该资源的用户”。
|
||||
|
||||
例如:
|
||||
|
||||
- `f.created_by`
|
||||
- `t.created_by`
|
||||
- `proposal.created_by`
|
||||
|
||||
### `owner_field`
|
||||
|
||||
表示“资源所有者”,和创建者不一定相同。
|
||||
|
||||
如果当前项目没有成熟 owner 模型,可以先不启用。
|
||||
|
||||
### `user_field`
|
||||
|
||||
用于用户本身或用户快照类数据。
|
||||
|
||||
例如:
|
||||
|
||||
- `u.id`
|
||||
- `e.user_id`
|
||||
|
||||
### `public_field`
|
||||
|
||||
表示是否公共可见。
|
||||
|
||||
例如:
|
||||
|
||||
- `dataset.is_public`
|
||||
- `app.is_public`
|
||||
|
||||
---
|
||||
|
||||
## 5. 各模块字段映射表
|
||||
|
||||
## 5.1 文档模块
|
||||
|
||||
主资源:`leaudit_documents d`
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `d.region` |
|
||||
| `creator_field` | `f.created_by` |
|
||||
| `owner_field` | 暂无 |
|
||||
| `user_field` | `f.created_by` |
|
||||
|
||||
说明:
|
||||
|
||||
- 当前代码事实口径就是 `d.region + f.created_by`
|
||||
- 文档的“自己数据”不建议改成 `d.created_by`,因为现有实现明显依赖文件记录
|
||||
|
||||
## 5.2 公文模块
|
||||
|
||||
主资源:`govdoc document / leaudit_documents d`
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `d.region` |
|
||||
| `creator_field` | `f.created_by` |
|
||||
| `user_field` | `f.created_by` |
|
||||
|
||||
说明:
|
||||
|
||||
- 公文 run、报告、原文都必须回溯到 `d.region` 和 `f.created_by`
|
||||
|
||||
## 5.3 使用统计模块
|
||||
|
||||
这块必须拆成两个口径。
|
||||
|
||||
### 用户口径统计
|
||||
|
||||
主资源:`sso_users u` 或 `usage_login_events e`
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `u.area` 或 `e.area_snapshot` |
|
||||
| `user_field` | `u.id` 或 `e.user_id` |
|
||||
|
||||
### 文档口径统计
|
||||
|
||||
主资源:文档上传/评查事件
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `d.region` |
|
||||
| `creator_field` | `f.created_by` |
|
||||
| `user_field` | `f.created_by` |
|
||||
|
||||
说明:
|
||||
|
||||
- `areaScope=user` 和 `areaScope=document` 本质上是两套字段映射切换
|
||||
- 不能在一个 builder 里靠字符串替换硬凑
|
||||
|
||||
## 5.4 合同模板模块
|
||||
|
||||
主资源:`contract_template t`
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `t.region` |
|
||||
| `creator_field` | `t.created_by` |
|
||||
| `public_field` | 暂无;如后续有省级公共模板逻辑,应单独建模 |
|
||||
|
||||
说明:
|
||||
|
||||
- 当前模块有“省级模板 + 本地区模板”可见语义
|
||||
- 这不是 `is_public`
|
||||
- 应在 `ContractTemplatePolicy` 中定义成“系统公共范围”,不要混同布尔公开字段
|
||||
|
||||
## 5.5 RBAC 用户管理
|
||||
|
||||
主资源:`sso_users u`
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `u.area` |
|
||||
| `user_field` | `u.id` |
|
||||
|
||||
说明:
|
||||
|
||||
- 角色对象本身不按 area
|
||||
- 但“查看哪个用户、给谁分配角色”按 `u.area`
|
||||
|
||||
## 5.6 RAG 模块
|
||||
|
||||
### 数据集
|
||||
|
||||
主资源:`dataset`
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `dataset.area` |
|
||||
| `creator_field` | `dataset.created_by` |
|
||||
| `public_field` | `dataset.is_public` |
|
||||
|
||||
### 聊天应用
|
||||
|
||||
主资源:`app`
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `area_field` | `app.area` |
|
||||
| `public_field` | `dataset.is_public` 或显式 `app.is_public` |
|
||||
|
||||
说明:
|
||||
|
||||
- 如果 app 的公开性来自关联 dataset,就要在 policy 层明确写清,不要分散在查询里隐式推断
|
||||
|
||||
## 5.7 交叉评查
|
||||
|
||||
主资源:任务关系,而不是单表字段。
|
||||
|
||||
推荐映射:
|
||||
|
||||
| 类型 | 字段 |
|
||||
| --- | --- |
|
||||
| `user_field` | `tm.user_id` |
|
||||
| `creator_field` | `proposal.created_by` |
|
||||
|
||||
说明:
|
||||
|
||||
- 交叉评查以 `RELATION` 模型处理
|
||||
- 这块不强制要求 `area_field`
|
||||
|
||||
---
|
||||
|
||||
## 6. Alias 统一规范
|
||||
|
||||
统一执行器要稳定接入,SQL alias 必须统一。
|
||||
|
||||
建议标准:
|
||||
|
||||
| 资源 | 推荐 alias |
|
||||
| --- | --- |
|
||||
| 文档主表 | `d` |
|
||||
| 文档文件表 | `f` |
|
||||
| 用户表 | `u` |
|
||||
| 审查运行表 | `r` |
|
||||
| 统计登录事件表 | `e` |
|
||||
| 合同模板表 | `t` |
|
||||
| RAG 数据集 | `dataset` |
|
||||
| RAG 应用 | `app` |
|
||||
| 交叉评查任务 | `task` |
|
||||
| 交叉评查成员 | `tm` |
|
||||
| 交叉评查提案 | `proposal` |
|
||||
|
||||
目的不是强迫重命名所有 SQL,而是:
|
||||
|
||||
- 新增或重构 SQL 时尽量统一
|
||||
- `QueryScopeBuilder` 和 `ModulePolicy` 才能更容易复用
|
||||
|
||||
---
|
||||
|
||||
## 7. 参数命名规范
|
||||
|
||||
当前代码里已经有:
|
||||
|
||||
- `requested_region`
|
||||
- `scope_region`
|
||||
- `scope_user_id`
|
||||
- `requested_user_id`
|
||||
|
||||
建议固化为统一标准:
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| `requested_area` | 请求方传入的地区过滤 |
|
||||
| `scope_area` | 当前 scope 决策后的有效地区 |
|
||||
| `requested_user_id` | 请求方显式筛选的用户 |
|
||||
| `scope_user_id` | scope 决策后的当前用户 ID |
|
||||
| `resource_id` | 主资源 ID |
|
||||
| `visible_areas` | `PUBLIC_MIXED` 或公共范围列表 |
|
||||
|
||||
不建议再混用:
|
||||
|
||||
- `query_area`
|
||||
- `user_area`
|
||||
- `region`
|
||||
- `scope_region`
|
||||
|
||||
除非当前模块确实已经固定使用 `region` 作为数据库字段名,而不是参数名。
|
||||
|
||||
建议规则:
|
||||
|
||||
- 参数命名一律使用 `area`
|
||||
- 数据库字段保留 `region/area` 原名
|
||||
|
||||
即:
|
||||
|
||||
```sql
|
||||
COALESCE(d.region, '') = :scope_area
|
||||
```
|
||||
|
||||
而不是:
|
||||
|
||||
```sql
|
||||
COALESCE(d.region, '') = :scope_region
|
||||
```
|
||||
|
||||
这样更利于统一执行器复用。
|
||||
|
||||
---
|
||||
|
||||
## 8. 标准 SQL 子句模板
|
||||
|
||||
## 8.1 `ALL`
|
||||
|
||||
无地区限制时:
|
||||
|
||||
```sql
|
||||
1 = 1
|
||||
```
|
||||
|
||||
带请求地区过滤时:
|
||||
|
||||
```sql
|
||||
COALESCE({area_field}, '') = :requested_area
|
||||
```
|
||||
|
||||
## 8.2 `DEPT`
|
||||
|
||||
```sql
|
||||
COALESCE({area_field}, '') = :scope_area
|
||||
```
|
||||
|
||||
并且在进入 SQL 前先做规则:
|
||||
|
||||
- 若 `requested_area` 非空且不等于 `scope_area`,直接拒绝或生成 `1 = 0`
|
||||
|
||||
## 8.3 `SELF`
|
||||
|
||||
```sql
|
||||
{creator_field} = :scope_user_id
|
||||
```
|
||||
|
||||
若请求还传了 `requested_user_id`:
|
||||
|
||||
- 与 `scope_user_id` 不相等时直接拒绝
|
||||
|
||||
## 8.4 `PUBLIC_MIXED`
|
||||
|
||||
```sql
|
||||
(
|
||||
COALESCE({area_field}, '') IN :visible_areas
|
||||
OR {public_field} = TRUE
|
||||
)
|
||||
```
|
||||
|
||||
推荐 `visible_areas` 至少包含:
|
||||
|
||||
- 当前用户地区
|
||||
- `省级`
|
||||
- `''`
|
||||
|
||||
具体由 `RagPolicy` 决定。
|
||||
|
||||
## 8.5 `RELATION`
|
||||
|
||||
不建议硬编码为通用模板。
|
||||
|
||||
应由 `CrossReviewPolicy` 输出,例如:
|
||||
|
||||
```sql
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_cross_review_task_member tm
|
||||
WHERE tm.task_id = task.id
|
||||
AND tm.user_id = :scope_user_id
|
||||
AND tm.deleted_at IS NULL
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 主资源回溯规范
|
||||
|
||||
这是本轮 SQL 改造里最重要的一条。
|
||||
|
||||
## 9.1 什么叫主资源回溯
|
||||
|
||||
当接口操作的不是主资源表,而是主资源衍生物时,必须回溯到主资源做 scope 判断。
|
||||
|
||||
## 9.2 必须回溯的场景
|
||||
|
||||
### 文档状态
|
||||
|
||||
虽然接口直接拿文档 ID 列表查状态,但本质仍是文档资源。
|
||||
|
||||
必须回溯:
|
||||
|
||||
- `document`
|
||||
- `file`
|
||||
|
||||
### 公文 run / report / original
|
||||
|
||||
不能只按:
|
||||
|
||||
- `run_id`
|
||||
- `artifact_id`
|
||||
- `document_id`
|
||||
|
||||
直接查。
|
||||
|
||||
必须回溯到:
|
||||
|
||||
- `govdoc document d`
|
||||
- `original file f`
|
||||
|
||||
### RAG dataset document / segment
|
||||
|
||||
不能只按:
|
||||
|
||||
- `document_id`
|
||||
- `segment_id`
|
||||
|
||||
直接做可见性判断。
|
||||
|
||||
必须回溯到:
|
||||
|
||||
- `dataset`
|
||||
|
||||
### 交叉评查 proposal export
|
||||
|
||||
不能只按 `DocumentId` 导出。
|
||||
|
||||
必须回溯到:
|
||||
|
||||
- 当前用户是否属于该任务关系链
|
||||
|
||||
---
|
||||
|
||||
## 10. 推荐接入方式
|
||||
|
||||
## 10.1 列表接口
|
||||
|
||||
推荐模式:
|
||||
|
||||
1. 构造基础查询
|
||||
2. 获取 `PermissionDecision`
|
||||
3. 由 `QueryScopeBuilder` 生成 `scope_clause`
|
||||
4. 将 `scope_clause.sql` 注入 `WHERE`
|
||||
5. 业务筛选条件作为附加条件继续追加
|
||||
|
||||
示意:
|
||||
|
||||
```python
|
||||
decision = await permissionScopeFacade.require(...)
|
||||
scope_clause = queryScopeBuilder.build_by_mapping(...)
|
||||
|
||||
where_clauses = [
|
||||
"d.deleted_at IS NULL",
|
||||
scope_clause.sql,
|
||||
]
|
||||
params = {
|
||||
**scope_clause.params,
|
||||
}
|
||||
```
|
||||
|
||||
## 10.2 详情接口
|
||||
|
||||
推荐模式:
|
||||
|
||||
不要先查,再判断。
|
||||
|
||||
而要直接:
|
||||
|
||||
```sql
|
||||
SELECT ...
|
||||
FROM ...
|
||||
WHERE id = :resource_id
|
||||
AND {scope_clause.sql}
|
||||
```
|
||||
|
||||
这样天然避免“查到了但后面忘记拒绝”的风险。
|
||||
|
||||
## 10.3 删除/更新接口
|
||||
|
||||
推荐两种方式:
|
||||
|
||||
### 方式 A:先用带 scope 的 SELECT 锁定资源
|
||||
|
||||
```sql
|
||||
SELECT id
|
||||
FROM ...
|
||||
WHERE id = :resource_id
|
||||
AND {scope_clause.sql}
|
||||
FOR UPDATE
|
||||
```
|
||||
|
||||
### 方式 B:直接带 scope 执行 UPDATE/DELETE
|
||||
|
||||
```sql
|
||||
UPDATE ...
|
||||
SET ...
|
||||
WHERE id = :resource_id
|
||||
AND {scope_clause.sql}
|
||||
```
|
||||
|
||||
建议优先用方式 A,更利于错误提示和审计。
|
||||
|
||||
## 10.4 下载/导出接口
|
||||
|
||||
推荐模式:
|
||||
|
||||
1. 先回溯主资源并带 scope 查出合法记录
|
||||
2. 再根据合法记录生成下载地址或导出文件
|
||||
|
||||
不允许:
|
||||
|
||||
1. 先按附件 ID 或 artifact ID 取到 OSS URL
|
||||
2. 再事后补判断
|
||||
|
||||
---
|
||||
|
||||
## 11. 统计聚合改造规范
|
||||
|
||||
统计类 SQL 最容易出错,因为不是简单查明细。
|
||||
|
||||
## 11.1 先收 scope,再聚合
|
||||
|
||||
推荐:
|
||||
|
||||
```sql
|
||||
WITH scoped_docs AS (
|
||||
SELECT d.id, d.region, f.created_by
|
||||
FROM ...
|
||||
WHERE ...
|
||||
AND {scope_clause.sql}
|
||||
)
|
||||
SELECT ...
|
||||
FROM scoped_docs
|
||||
GROUP BY ...
|
||||
```
|
||||
|
||||
不推荐:
|
||||
|
||||
先全量聚合,再在外层做地区过滤。
|
||||
|
||||
原因:
|
||||
|
||||
- 易错
|
||||
- 性能差
|
||||
- `SELF` 范围很容易被漏掉
|
||||
|
||||
## 11.2 用户口径和文档口径必须拆分
|
||||
|
||||
不要写一个函数同时隐式支持:
|
||||
|
||||
- `u.area`
|
||||
- `d.region`
|
||||
- `e.area_snapshot`
|
||||
|
||||
建议明确:
|
||||
|
||||
- `build_user_area_scope_clause()`
|
||||
- `build_document_area_scope_clause()`
|
||||
- `build_login_snapshot_scope_clause()`
|
||||
|
||||
或者在 `UsageStatsPolicy` 内按口径分发。
|
||||
|
||||
---
|
||||
|
||||
## 12. 反模式清单
|
||||
|
||||
以下写法在本轮改造中应视为禁用或逐步清理对象。
|
||||
|
||||
## 12.1 反模式:角色名直接拼 SQL 范围
|
||||
|
||||
```sql
|
||||
bool_or(r.role_key IN ('super_admin', 'provincial_admin'))
|
||||
```
|
||||
|
||||
问题:
|
||||
|
||||
- 角色名直接耦合能力
|
||||
- 新角色无法扩展
|
||||
|
||||
## 12.2 反模式:详情先查后判
|
||||
|
||||
```python
|
||||
row = await session.execute(...)
|
||||
if row and current_user["can_manage"]:
|
||||
...
|
||||
```
|
||||
|
||||
问题:
|
||||
|
||||
- 非法资源已经被读出来
|
||||
- 派生接口最容易漏判
|
||||
|
||||
## 12.3 反模式:用 `1 = 0` 到处散落表达拒绝
|
||||
|
||||
`1 = 0` 可以作为最终 SQL 结果,但不应成为业务逻辑表达方式。
|
||||
|
||||
更推荐:
|
||||
|
||||
- 在决策层直接拒绝
|
||||
- 或由 builder 明确返回 `denied clause`
|
||||
|
||||
## 12.4 反模式:同一模块 area 字段口径漂移
|
||||
|
||||
例如:
|
||||
|
||||
- 文档列表按 `u.area`
|
||||
- 文档详情按 `d.region`
|
||||
|
||||
这种写法必须统一。
|
||||
|
||||
## 12.5 反模式:下载 URL 先取后判
|
||||
|
||||
尤其是:
|
||||
|
||||
- 原文下载
|
||||
- 报告下载
|
||||
- 导出文件
|
||||
|
||||
必须先判 scope,再产出 URL。
|
||||
|
||||
---
|
||||
|
||||
## 13. 索引建议
|
||||
|
||||
统一执行器接入后,范围过滤会更集中,需要补齐索引。
|
||||
|
||||
建议优先确认以下索引:
|
||||
|
||||
### 文档/公文
|
||||
|
||||
- `documents(region)`
|
||||
- `document_files(created_by)`
|
||||
- `document_files(document_id, created_by)`
|
||||
|
||||
### 用户
|
||||
|
||||
- `sso_users(area)`
|
||||
- `sso_users(status, deleted_at, area)`
|
||||
|
||||
### 合同模板
|
||||
|
||||
- `contract_templates(region)`
|
||||
- `contract_templates(created_by)`
|
||||
|
||||
### RAG
|
||||
|
||||
- `rag_datasets(area, is_public)`
|
||||
- `rag_apps(area)`
|
||||
|
||||
### 交叉评查
|
||||
|
||||
- `task_member(task_id, user_id)`
|
||||
- `proposal(document_id, created_by)`
|
||||
|
||||
说明:
|
||||
|
||||
- 索引不是这轮文档的主体,但如果没有,会直接影响统一执行器上线后的查询性能
|
||||
|
||||
---
|
||||
|
||||
## 14. 推荐代码组织
|
||||
|
||||
建议新增或统一下面这类方法:
|
||||
|
||||
```python
|
||||
build_scope_clause_for_document(...)
|
||||
build_scope_clause_for_user(...)
|
||||
build_scope_clause_for_dataset(...)
|
||||
resolve_primary_resource_scope(...)
|
||||
```
|
||||
|
||||
更推荐的最终形态是:
|
||||
|
||||
```python
|
||||
decision = await permissionDecisionService.decide(ctx)
|
||||
scope_clause = modulePolicy.build_clause(ctx, decision)
|
||||
```
|
||||
|
||||
这样业务 service 只负责:
|
||||
|
||||
1. 自身业务查询
|
||||
2. 接入 scope 子句
|
||||
3. 做结果组装
|
||||
|
||||
而不是自己解释权限模型。
|
||||
|
||||
---
|
||||
|
||||
## 15. 分模块改造建议
|
||||
|
||||
## 15.1 文档与公文
|
||||
|
||||
优先动作:
|
||||
|
||||
1. 抽出统一 `DocumentScopeMapping`
|
||||
2. 统一 `d.region + f.created_by`
|
||||
3. 所有详情/状态/run/report/download 统一回溯主文档
|
||||
|
||||
## 15.2 使用统计
|
||||
|
||||
优先动作:
|
||||
|
||||
1. 拆分用户口径和文档口径
|
||||
2. 不再通过字符串替换实现 `area_snapshot`
|
||||
3. 将 `SELF` 范围明确化
|
||||
|
||||
## 15.3 合同模板
|
||||
|
||||
优先动作:
|
||||
|
||||
1. 把“省级模板可见”收敛为 policy
|
||||
2. 列表/搜索/详情共享同一范围规则
|
||||
|
||||
## 15.4 RBAC 用户管理
|
||||
|
||||
优先动作:
|
||||
|
||||
1. 用户列表、组织树、角色分配统一按 `u.area`
|
||||
2. 角色元数据接口不强加 area scope
|
||||
|
||||
## 15.5 RAG
|
||||
|
||||
优先动作:
|
||||
|
||||
1. `PUBLIC_MIXED` 统一化
|
||||
2. dataset 子资源全部回溯 dataset
|
||||
|
||||
---
|
||||
|
||||
## 16. 最终要求
|
||||
|
||||
后续所有权限改造相关 SQL,应满足以下要求:
|
||||
|
||||
1. 能明确说清主资源是谁
|
||||
2. 能明确说清 `area_field` 和 `creator_field` 是哪个
|
||||
3. 能明确说清详情/下载/导出是否回溯主资源
|
||||
4. 不再依赖角色名派生范围
|
||||
5. 新增接口时可以直接挂到统一执行器,而不是复制旧判断
|
||||
|
||||
如果做不到这 5 条,即使逻辑暂时跑通,也不算完成“统一权限架构”的 SQL 层落地。
|
||||
Reference in New Issue
Block a user