1520 lines
39 KiB
Markdown
1520 lines
39 KiB
Markdown
# 权限架构全面优化改造方案
|
||
|
||
> 适用范围:`leaudit-platform` 当前“角色权限 + 地区隔离”体系
|
||
> 目标:在不推翻现有 RBAC 表结构和已落地业务逻辑的前提下,把分散的权限判断、数据范围控制、菜单兼容逻辑收敛为一套可持续演进的平台化能力。
|
||
|
||
---
|
||
|
||
## 1. 结论先行
|
||
|
||
当前项目的权限架构不是“缺权限系统”,而是已经形成了比较清晰的主干:
|
||
|
||
- 认证层:`JWT + sso_users`
|
||
- 功能权限层:`roles / user_role / permissions / role_permissions`
|
||
- 菜单权限层:`sys_routes / role_route`
|
||
- 数据隔离层:`area + role/data_scope + 业务模块自定义过滤`
|
||
|
||
从现状看,项目的真实成熟度是:
|
||
|
||
- **功能权限成熟度较高**
|
||
- **菜单权限已基本成型,但仍有兼容 fallback**
|
||
- **数据范围权限设计完整,但平台统一执行能力不足**
|
||
- **部分模块已经自行实现范围控制,但实现风格不统一**
|
||
|
||
因此,本次改造**不建议推翻现有表设计重做**,而应采取“保留模型、统一执行、逐步收敛”的路径:
|
||
|
||
1. 保留现有 `RBAC + 单地区隔离` 总体模型
|
||
2. 新增统一的“数据范围解析器 + 查询过滤构建器”
|
||
3. 将业务模块里的手写 `is_global/can_manage/area/created_by` 逻辑逐步平台化
|
||
4. 逐步取消前后端路由 fallback,最终只认数据库路由与权限点
|
||
5. 将“管理能力”从角色硬编码逐步迁移到显式权限点驱动
|
||
6. 对 legacy 模块和特殊访问模型做分层治理,而不是强行一刀切
|
||
|
||
---
|
||
|
||
## 2. 当前代码架构全景
|
||
|
||
## 2.1 认证与登录态
|
||
|
||
当前 JWT 只保留鉴权链路所需的最小字段,不把完整 `roles/permissions` 写进 token。
|
||
|
||
关键实现:
|
||
|
||
- `fastapi_common/fastapi_common_security/jwtService.py`
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py`
|
||
|
||
已确认的行为:
|
||
|
||
- JWT 中保存:`user_id`、`username`、`area`、`user_role` 等最小身份信息
|
||
- 登录响应和 `/auth/me` 返回完整 `roles`、`permissions`
|
||
- 这样避免了权限过多导致前端 session/cookie 体积膨胀
|
||
|
||
这是合理设计,应保留。
|
||
|
||
## 2.2 RBAC 核心数据模型
|
||
|
||
当前权限核心表由 `scripts/创建sql/user_rbac_schema_patch.sql` 定义,结构完整,且和现有业务实现一致:
|
||
|
||
- `sso_users`
|
||
- `roles`
|
||
- `user_role`
|
||
- `sys_routes`
|
||
- `role_route`
|
||
- `permissions`
|
||
- `role_permissions`
|
||
|
||
其中最关键的设计语义是:
|
||
|
||
- 用户地区主字段:`sso_users.area`
|
||
- 角色默认数据范围:`roles.data_scope`
|
||
- 角色-权限点级数据范围:`role_permissions.data_scope`
|
||
- 拒绝优先机制:`role_permissions.grant_type = GRANT / DENY`
|
||
- `DEPT` 在本项目语义里其实是“同地区”,不是传统组织部门
|
||
|
||
这套模型本身没有明显结构性错误,问题主要出在“平台执行层不统一”。
|
||
|
||
## 2.3 后端功能权限校验
|
||
|
||
当前后端权限判断主要分两类:
|
||
|
||
1. 通用 permission 校验
|
||
2. 某些管理域额外加角色型上下文判断
|
||
|
||
关键实现:
|
||
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py`
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/rbacAdminServiceImpl.py`
|
||
|
||
现状特点:
|
||
|
||
- `PermissionServiceImpl` 已支持:
|
||
- 数据库动态查权
|
||
- `DENY` 优先
|
||
- wildcard 权限匹配
|
||
- 但它**只返回“有没有该权限点”**,**不解析 data_scope**
|
||
|
||
这意味着:
|
||
|
||
- 平台层只完成了“功能准入”
|
||
- 没完成“数据范围落地”
|
||
|
||
## 2.4 菜单与页面权限
|
||
|
||
当前菜单权限总体是数据库驱动,但仍带兼容降级逻辑。
|
||
|
||
关键实现:
|
||
|
||
- 后端:`fastapi_modules/fastapi_leaudit/services/impl/rbacServiceImpl.py`
|
||
- 前端:`legal-platform-frontend/lib/api/legacy/auth/user-routes.ts`
|
||
- 前端侧边栏:`legal-platform-frontend/components/layout/Sidebar.tsx`
|
||
|
||
现状行为:
|
||
|
||
- 后端优先从 `role_route + sys_routes` 生成当前用户路由树
|
||
- 若数据库路由集合未达到“前端真实路径集”的预期,则回退到 `_COMPAT_ROUTE_BLUEPRINTS`
|
||
- 前端仍保留静态 fallback menu 和本地权限 map 兼容逻辑
|
||
|
||
这说明系统已经向“数据库驱动权限菜单”演进,但尚未完全完成切换。
|
||
|
||
## 2.5 数据范围控制
|
||
|
||
当前数据范围控制最关键的事实是:
|
||
|
||
- **设计层已经有 data_scope**
|
||
- **平台层没有统一数据范围执行器**
|
||
- **业务层各模块自行实现范围过滤**
|
||
|
||
已确认的代表实现:
|
||
|
||
- 文档:`fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py`
|
||
- 公文:`fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py`
|
||
- 统计:`fastapi_modules/fastapi_leaudit/services/impl/usageStatsServiceImpl.py`
|
||
|
||
这些模块大量采用类似逻辑:
|
||
|
||
- `is_global` => 全量
|
||
- `can_manage + area` => 本地区
|
||
- 普通用户 => `created_by/current_user_id`
|
||
|
||
这套逻辑本身没有错,但它是“业务重复实现”,不是“权限平台统一执行”。
|
||
|
||
## 2.6 特殊模块访问模型
|
||
|
||
项目里并非所有模块都纯粹按 `area + data_scope` 控制,存在三类特殊形态:
|
||
|
||
### 2.6.1 RAG 模块
|
||
|
||
关键实现:
|
||
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/ragDatasetServiceImpl.py`
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/ragChatServiceImpl.py`
|
||
|
||
访问特点:
|
||
|
||
- 管理侧按 `UserRole + UserArea` 控制可管理知识库范围
|
||
- 使用侧按 `area in (user_area, '省级', '') or is_public` 控制可见应用和知识库
|
||
- 这是一种“地区 + 公共可见”混合模型
|
||
|
||
### 2.6.2 交叉评查模块
|
||
|
||
关键实现:
|
||
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/crossReviewServiceImpl.py`
|
||
|
||
访问特点:
|
||
|
||
- 主要按“任务成员关系”控制
|
||
- 用户是否能看任务、提案、投票、文档,核心依赖 `task_member`
|
||
- 这不是纯 area 访问模型,而是典型 ABAC/关系型访问模型
|
||
|
||
### 2.6.3 规则与规则配置模块
|
||
|
||
关键实现:
|
||
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/ruleServiceImpl.py`
|
||
- `fastapi_modules/fastapi_leaudit/services/impl/ruleConfigServiceImpl.py`
|
||
|
||
访问特点:
|
||
|
||
- 更偏“配置域”和“元数据域”
|
||
- 当前更多依赖功能权限,不强依赖 area/data_scope
|
||
- 但与评查点分组、文档类型、入口模块存在管理域耦合
|
||
|
||
---
|
||
|
||
## 3. 当前架构的优点
|
||
|
||
## 3.1 主模型已经稳定
|
||
|
||
项目已经从复杂化、多地区、多入口的旧思路收敛到:
|
||
|
||
- 一个用户一个主地区
|
||
- 少量角色
|
||
- 菜单权限和动作权限分层
|
||
- 数据权限依赖地区和用户归属
|
||
|
||
这个方向是正确的。
|
||
|
||
## 3.2 功能权限表设计足够支撑未来扩展
|
||
|
||
当前 `permissions + role_permissions` 已经具备:
|
||
|
||
- API 权限点建模
|
||
- route 关联能力
|
||
- `GRANT / DENY`
|
||
- `data_scope`
|
||
- `condition_filter`
|
||
|
||
说明现有模型不是只能做静态角色,而是具备平台化扩展空间。
|
||
|
||
## 3.3 多个业务模块已经形成真实可用的数据隔离逻辑
|
||
|
||
虽然还不统一,但文档、公文、统计等核心模块已经不是裸奔状态。
|
||
|
||
这带来两个好处:
|
||
|
||
- 当前系统并非需要从零补安全
|
||
- 可直接抽象这些已验证逻辑,作为统一执行器的来源
|
||
|
||
## 3.4 登录态瘦身思路正确
|
||
|
||
JWT 只存最小字段、详细身份通过接口返回,这一点对后续权限扩展非常重要,应保持不变。
|
||
|
||
---
|
||
|
||
## 4. 当前关键问题与风险
|
||
|
||
## 4.1 最大问题:`data_scope` 已建模,但没有平台级统一执行
|
||
|
||
这是整个权限架构当前最大的结构性缺口。
|
||
|
||
现象:
|
||
|
||
- `roles.data_scope`、`role_permissions.data_scope` 已存在
|
||
- 但 `PermissionServiceImpl` 不返回 scope
|
||
- 业务层查询时拿不到统一 scope 解析结果
|
||
- 各业务模块只能自己写过滤逻辑
|
||
|
||
后果:
|
||
|
||
- 同一权限点在不同模块中可能出现不同数据边界
|
||
- 新模块开发时容易漏加范围过滤
|
||
- 审计和排查越权时需要逐模块人工追代码
|
||
- 无法形成统一测试基线
|
||
|
||
## 4.2 第二大问题:管理能力仍部分依赖角色硬编码
|
||
|
||
典型例子:
|
||
|
||
- `documentServiceImpl.py`
|
||
- `rbacAdminServiceImpl.py`
|
||
- `ragDatasetServiceImpl.py`
|
||
|
||
这些实现大量依赖:
|
||
|
||
- `role_key in ('super_admin', 'provincial_admin')`
|
||
- `role_key in ('super_admin', 'provincial_admin', 'admin')`
|
||
|
||
风险:
|
||
|
||
- 后续若新增“某领域管理员”或更细角色,代码要到处改
|
||
- 角色含义和权限含义耦合
|
||
- 难以实现真正的“显式授权优先”
|
||
|
||
## 4.3 菜单权限仍存在 fallback 路径
|
||
|
||
这会带来两个风险:
|
||
|
||
1. 数据库配置与前端实际展示不完全一致
|
||
2. “菜单看得见/看不见”与“数据库已授权/未授权”之间可能出现认知偏差
|
||
|
||
虽然 fallback 是合理的迁移兼容机制,但不应长期存在于最终架构中。
|
||
|
||
## 4.4 数据范围规则语义未彻底统一
|
||
|
||
当前系统里至少并存以下几种语义:
|
||
|
||
- `ALL / DEPT / SELF`
|
||
- `is_global / can_manage / is_super_admin`
|
||
- `area`
|
||
- `created_by`
|
||
- `owner`
|
||
- `public`
|
||
- `task_member`
|
||
|
||
这些语义没有错,但缺少统一分类:
|
||
|
||
- 哪些属于通用 scope
|
||
- 哪些属于模块级关系规则
|
||
- 哪些属于资源属性规则
|
||
|
||
这会使平台边界越来越模糊。
|
||
|
||
## 4.5 legacy 模块治理程度不一致
|
||
|
||
评查点、规则、旧库桥接模块仍带有比较重的历史包袱,典型风险包括:
|
||
|
||
- 仍依赖旧库结构
|
||
- 通过参数而不是统一 user context 控制 area
|
||
- 控制器层做了 permission 校验,但服务层范围收口不足
|
||
|
||
这种模块最容易成为越权和维护复杂度的来源。
|
||
|
||
## 4.6 缺少统一的权限可观测性
|
||
|
||
当前系统基本没有形成统一的:
|
||
|
||
- 权限命中日志
|
||
- data_scope 解析日志
|
||
- 被拒绝原因模型
|
||
- 权限矩阵巡检工具
|
||
|
||
结果是:
|
||
|
||
- 越权排查慢
|
||
- 权限配置错误定位难
|
||
- 测试覆盖很难自动化
|
||
|
||
---
|
||
|
||
## 5. 目标架构设计
|
||
|
||
## 5.1 总体原则
|
||
|
||
目标架构不是“把所有访问控制都压成一个万能函数”,而是分三层:
|
||
|
||
1. **功能权限层**
|
||
- 判断用户能不能调用某个动作
|
||
2. **通用数据范围层**
|
||
- 判断该动作默认可以看到哪些数据
|
||
3. **模块关系规则层**
|
||
- 处理 `public`、`task_member`、`owner`、`state` 这类非通用访问规则
|
||
|
||
最终形成:
|
||
|
||
- RBAC 负责“能不能做”
|
||
- Scope Resolver 负责“默认能看多少”
|
||
- Module Policy 负责“该模块的特殊访问规则”
|
||
|
||
## 5.2 建议新增的核心组件
|
||
|
||
建议在后端新增一组统一能力:
|
||
|
||
### 5.2.1 `PermissionDecisionService`
|
||
|
||
职责:
|
||
|
||
- 输入:`user_id + permission_key`
|
||
- 输出:完整授权决策对象,而不是简单布尔值
|
||
|
||
建议返回:
|
||
|
||
- `allowed`
|
||
- `grant_source_roles`
|
||
- `grant_type`
|
||
- `effective_data_scope`
|
||
- `condition_filter`
|
||
- `is_super_admin`
|
||
|
||
### 5.2.2 `DataScopeResolver`
|
||
|
||
职责:
|
||
|
||
- 解析用户当前对某权限点的最终数据范围
|
||
|
||
规则建议:
|
||
|
||
1. 汇总用户所有命中角色
|
||
2. 处理 `DENY` 优先
|
||
3. 若权限点级 `data_scope` 存在,优先使用权限点级规则
|
||
4. 若不存在,回退到角色默认 `roles.data_scope`
|
||
5. 多角色命中时,对 `GRANT` 结果按最大可见范围求并集
|
||
|
||
建议统一优先级:
|
||
|
||
- `ALL > DEPT > SELF`
|
||
|
||
`GROUP` 当前仅保留兼容,不建议作为第一阶段重点。
|
||
|
||
### 5.2.3 `ScopeContextProvider`
|
||
|
||
职责:
|
||
|
||
- 统一加载当前用户上下文
|
||
|
||
建议提供:
|
||
|
||
- `user_id`
|
||
- `area`
|
||
- `roles`
|
||
- `is_super_admin`
|
||
- `is_global_admin`
|
||
- `is_area_admin`
|
||
|
||
注意:这里的 `is_global_admin/is_area_admin` 只是兼容派生属性,不能替代显式权限本身。
|
||
|
||
### 5.2.4 `QueryScopeBuilder`
|
||
|
||
职责:
|
||
|
||
- 把 scope 结果编译成 SQLAlchemy/SQL 过滤条件
|
||
|
||
建议能力:
|
||
|
||
- `apply_area_scope(table.region)`
|
||
- `apply_creator_scope(table.created_by)`
|
||
- `apply_owner_scope(table.owner_id)`
|
||
- `apply_union_scope(...)`
|
||
- `apply_public_fallback(...)`
|
||
|
||
这样业务模块不再自己拼接“同样一套 if/else”。
|
||
|
||
### 5.2.5 `ModulePolicy`
|
||
|
||
职责:
|
||
|
||
- 承接模块级特殊规则
|
||
|
||
例如:
|
||
|
||
- `CrossReviewPolicy`:任务成员可见
|
||
- `RagDatasetPolicy`:地区可见 + 公开资源可见
|
||
- `RuleConfigPolicy`:配置域权限,不强制 area
|
||
|
||
这一步非常关键,因为它避免把所有特殊访问规则硬塞进通用 data_scope。
|
||
|
||
---
|
||
|
||
## 6. 分层改造方案
|
||
|
||
## 6.1 认证层改造
|
||
|
||
### 保留
|
||
|
||
- JWT 只存最小身份字段
|
||
- 完整角色/权限通过 `/auth/me` 和登录响应返回
|
||
|
||
### 优化项
|
||
|
||
1. 增加统一身份上下文对象
|
||
2. 登录/鉴权后将 `user_id/area/user_role/roles` 统一注入请求上下文
|
||
3. 补充权限版本号或 identity revision 字段,便于缓存失效
|
||
4. 为 `/auth/me` 增加可观测字段:
|
||
- `roles`
|
||
- `permissions`
|
||
- `primary_role`
|
||
- `area`
|
||
|
||
### 不建议做的事
|
||
|
||
- 不建议把全部权限点重新塞回 JWT
|
||
- 不建议让前端自己根据角色推导数据范围
|
||
|
||
## 6.2 RBAC 模型层改造
|
||
|
||
### 保留
|
||
|
||
- 现有 7 张核心权限表
|
||
|
||
### 优化项
|
||
|
||
1. 明确 `DEPT` 在项目中的正式定义就是“同地区”
|
||
2. 明确 `GROUP` 仅兼容保留,除非有真实业务场景再启用
|
||
3. 为 `permissions` 增加更强的治理约束:
|
||
- 命名规范
|
||
- route 绑定规范
|
||
- 是否参与 data_scope 控制
|
||
4. 为 `role_permissions` 制定使用规则:
|
||
- 默认只用 `GRANT`
|
||
- `DENY` 只用于少数高风险覆盖场景
|
||
- `data_scope` 必须显式说明是否覆盖角色默认范围
|
||
|
||
### 建议新增字段
|
||
|
||
如后续需要,可增量补充:
|
||
|
||
- `permissions.scope_strategy`
|
||
- `none`
|
||
- `area`
|
||
- `creator`
|
||
- `owner`
|
||
- `module_policy`
|
||
- `permissions.resource_code`
|
||
- 标记该权限点对应的数据资源模型
|
||
|
||
这不是第一阶段必须项,但非常利于后续平台化。
|
||
|
||
## 6.3 权限决策层改造
|
||
|
||
建议把当前 `PermissionServiceImpl` 从:
|
||
|
||
- `CheckPermission(UserId, PermissionKey) -> bool`
|
||
|
||
扩展为:
|
||
|
||
- `GetPermissionDecision(UserId, PermissionKey) -> PermissionDecision`
|
||
|
||
旧布尔接口保留,作为新决策接口的简化包装。
|
||
|
||
建议新对象至少包括:
|
||
|
||
- `allowed`
|
||
- `effective_scope`
|
||
- `granted_by_roles`
|
||
- `denied_by_roles`
|
||
- `condition_filter`
|
||
|
||
这样业务代码就不再需要:
|
||
|
||
- 先查 permission
|
||
- 再自己查角色
|
||
- 再自己推导 scope
|
||
|
||
## 6.4 数据范围执行层改造
|
||
|
||
这是本次改造优先级最高的部分。
|
||
|
||
### 第一步:沉淀统一 scope 语义
|
||
|
||
统一三类通用 scope:
|
||
|
||
- `ALL`
|
||
- `DEPT`
|
||
- `SELF`
|
||
|
||
统一基础含义:
|
||
|
||
- `ALL`:不过滤地区/用户
|
||
- `DEPT`:按 `业务表地区字段 = 当前用户.area`
|
||
- `SELF`:按 `created_by / owner_id / uploaded_by = 当前用户.id`
|
||
|
||
### 第二步:沉淀统一查询构建器
|
||
|
||
把文档、公文、统计中已经重复出现的模式抽象出来,避免每个模块重复写:
|
||
|
||
- `if is_global`
|
||
- `if can_manage`
|
||
- `else current_user`
|
||
|
||
### 第三步:支持“通用 scope + 模块 policy”组合
|
||
|
||
例如:
|
||
|
||
- 文档:scope 直接决定
|
||
- RAG:scope + `is_public`
|
||
- 交叉评查:scope 不是主轴,改由 task-member policy 主导
|
||
|
||
## 6.5 前端权限消费层改造
|
||
|
||
目标是让前端变成“消费后端权限结果”,而不是“自己做权限解释器”。
|
||
|
||
### 改造目标
|
||
|
||
1. 前端菜单只消费后端 `/rbac/user/routes`
|
||
2. 前端不再长期依赖静态 fallback menu
|
||
3. `permission_map` 只作为缓存,不作为真相源
|
||
4. 页面级和按钮级权限统一从同一权限模型读取
|
||
|
||
### 渐进策略
|
||
|
||
1. 先补齐数据库路由集合
|
||
2. 再让后端 `GetCurrentUserRoutes` 永远走数据库分支
|
||
3. 最后删除前后端 fallback 蓝图和静态菜单
|
||
|
||
## 6.6 管理后台配置层改造
|
||
|
||
当前 RBAC 管理模块已经具备较强基础,但应继续完善为“可运营权限中心”。
|
||
|
||
建议新增或加强:
|
||
|
||
1. 角色数据范围可视化
|
||
2. 权限点是否覆盖角色默认范围的展示
|
||
3. 某角色最终可见菜单、权限点、scope 的预览
|
||
4. 某用户最终权限展开页
|
||
5. 权限冲突检测
|
||
6. 未绑定 route 的 permission 提示
|
||
7. 已配置但代码未消费的 permission 提示
|
||
|
||
---
|
||
|
||
## 7. 重点模块改造建议
|
||
|
||
## 7.1 文档模块
|
||
|
||
当前状态:
|
||
|
||
- 数据范围实现较成熟
|
||
- 逻辑已具备抽象价值
|
||
|
||
建议:
|
||
|
||
1. 把 `_getCurrentUserContext` 提升为公共能力
|
||
2. 把 `_buildDocumentScopeFilters` 抽到统一 `QueryScopeBuilder`
|
||
3. 文档列表、详情、历史版本、删除、评查结果全部统一走同一 scope 解析逻辑
|
||
4. 把 `created_by`、`region`、交叉评查任务访问拆成:
|
||
- 通用文档 scope
|
||
- 跨任务关系访问补充
|
||
|
||
目标:
|
||
|
||
- 文档模块作为第一批标准化样板模块
|
||
|
||
## 7.2 公文模块
|
||
|
||
当前状态:
|
||
|
||
- 与文档模块类似,也已有地区/用户过滤实现
|
||
|
||
建议:
|
||
|
||
1. 复用文档统一 scope builder
|
||
2. 不再保留模块私有版本的同构过滤逻辑
|
||
3. 把差异保留在字段映射层,而不是权限判断层
|
||
|
||
## 7.3 统计模块
|
||
|
||
当前状态:
|
||
|
||
- 已有 area/user/document 维度过滤
|
||
- 对数据口径一致性要求高
|
||
|
||
建议:
|
||
|
||
1. 明确“统计可见范围必须不大于源数据可见范围”
|
||
2. 所有统计查询先通过同一 scope resolver 得到可见边界
|
||
3. 再在统计 SQL 中应用该边界
|
||
4. 对 overview/trends/by-users/by-areas/details 建立统一基线测试
|
||
|
||
## 7.4 RAG 模块
|
||
|
||
当前状态:
|
||
|
||
- 使用了 `UserArea + UserRole + is_public`
|
||
- 具备自己的可见性模型
|
||
|
||
建议:
|
||
|
||
1. 把 RAG 归类为“area + public mixed policy”
|
||
2. 通用层负责给出:
|
||
- 当前用户是否全省
|
||
- 当前用户地区
|
||
- 当前 permission 的基础 scope
|
||
3. RAG 模块 policy 再补:
|
||
- `is_public = TRUE` 时的跨区可见
|
||
- `'省级'`、空地区默认资源的可见规则
|
||
4. 后续将“是否可管理知识库”从角色硬编码逐步迁移到显式 permission 决策
|
||
|
||
目标:
|
||
|
||
- RAG 继续保留业务特性,但不再分散复制 `UserRole` 判断
|
||
|
||
## 7.5 交叉评查模块
|
||
|
||
当前状态:
|
||
|
||
- 主要按任务成员关系控制
|
||
- 属于关系型访问控制,不应生硬纳入 `ALL/DEPT/SELF`
|
||
|
||
建议:
|
||
|
||
1. 将其定义为独立 `CrossReviewPolicy`
|
||
2. `permission_key` 只决定用户能否进入该功能域
|
||
3. 具体资源访问由:
|
||
- `task_member`
|
||
- `assigner`
|
||
- `principal`
|
||
- `proposal_owner`
|
||
等关系决定
|
||
4. 需要补充与文档主访问边界的关系定义:
|
||
- 交叉评查任务中的文档是否可突破原始文档 `SELF`
|
||
- 若可突破,突破边界必须仅限任务上下文
|
||
|
||
目标:
|
||
|
||
- 把交叉评查明确定位为“关系型权限域”,而不是强行纳入普通地区 scope
|
||
|
||
## 7.6 评查点 / 规则 / legacy 模块
|
||
|
||
当前状态:
|
||
|
||
- 部分实现仍偏 legacy
|
||
- 与旧库桥接较多
|
||
- 权限收口不够彻底
|
||
|
||
建议:
|
||
|
||
1. 先做权限与数据流梳理
|
||
2. 梳理所有入口:
|
||
- 列表
|
||
- 详情
|
||
- 新增
|
||
- 更新
|
||
- 删除
|
||
- 导入导出
|
||
3. 对每个接口明确:
|
||
- 只需要功能权限
|
||
- 还是还要 data_scope
|
||
4. 对旧库访问统一增加 user context 入参约束
|
||
5. 禁止仅依赖外部传入 `area` 参数作为最终数据边界
|
||
|
||
---
|
||
|
||
## 8. 管理权限治理方案
|
||
|
||
当前系统里“能否管理”仍较多通过角色推导:
|
||
|
||
- `provincial_admin`
|
||
- `admin`
|
||
- `super_admin`
|
||
|
||
建议分两阶段治理。
|
||
|
||
## 8.1 第一阶段
|
||
|
||
保留现有角色硬编码兼容判断,但所有新功能必须同时引入显式 permission。
|
||
|
||
即:
|
||
|
||
- 角色硬编码只作为兼容 guard
|
||
- 新方案以 permission 为主
|
||
|
||
## 8.2 第二阶段
|
||
|
||
将“管理能力”全面迁移为权限点驱动:
|
||
|
||
- `system:settings:manage`
|
||
- `rbac:role_permissions:write`
|
||
- `rag:dataset:manage`
|
||
- `rules:config:manage`
|
||
|
||
最终目标:
|
||
|
||
- “你是不是 admin”不再直接等于“你能不能管理 X”
|
||
- 改成“你是否拥有该领域管理权限”
|
||
|
||
---
|
||
|
||
## 9. 硬编码角色改造专项分析
|
||
|
||
这部分必须单独拿出来,因为它不是“代码风格问题”,而是当前权限架构演进时最大的联动风险来源之一。
|
||
|
||
当前项目中的角色硬编码,至少存在 4 种不同形态:
|
||
|
||
1. **服务层派生上下文硬编码**
|
||
2. **服务层直接放行业务动作硬编码**
|
||
3. **前端展示/编辑能力硬编码**
|
||
4. **前端 guard / fallback / role mapping 硬编码**
|
||
|
||
如果不把这 4 类拆开治理,只改其中一层,会出现“后端收敛了,前端仍按旧角色逻辑放大/缩小能力”的不一致问题。
|
||
|
||
## 9.1 已确认的后端硬编码角色热点
|
||
|
||
### A. 通用上下文派生型
|
||
|
||
这些地方不是直接判断某个 permission,而是先把角色硬编码推导为:
|
||
|
||
- `is_global`
|
||
- `can_manage`
|
||
- `is_super_admin`
|
||
- `bypass_area`
|
||
|
||
代表位置:
|
||
|
||
- `documentServiceImpl.py`
|
||
- `govdocServiceImpl.py`
|
||
- `usageStatsServiceImpl.py`
|
||
- `contractTemplateServiceImpl.py`
|
||
- `rbacAdminServiceImpl.py`
|
||
- `homeServiceImpl.py`
|
||
|
||
典型模式:
|
||
|
||
- `role_key IN ('super_admin', 'provincial_admin') => is_global`
|
||
- `role_key IN ('super_admin', 'provincial_admin', 'admin') => can_manage`
|
||
- `role_key = 'super_admin' => is_super_admin / bypass_area`
|
||
|
||
问题本质:
|
||
|
||
- 这是把“角色名称”直接当成“能力模型”
|
||
- 后续新增任意领域型管理员时,所有上下文派生代码都得重复修改
|
||
|
||
### B. RAG 管理动作直判型
|
||
|
||
代表位置:
|
||
|
||
- `ragDatasetServiceImpl.py`
|
||
- `ragChatServiceImpl.py`
|
||
|
||
典型模式:
|
||
|
||
- `UserRole not in ("provincial_admin", "admin", "super_admin")`
|
||
- `user_role == "provincial_admin"`
|
||
- `UserRole == "admin"`
|
||
|
||
问题本质:
|
||
|
||
- 控制器层已经有 permission 校验
|
||
- 服务层又追加了一层角色白名单校验
|
||
- 结果是“permission 允许但角色名不在白名单”时仍会被拒绝
|
||
|
||
这会直接阻断未来“非 admin 角色但拥有 RAG 管理权限”的扩展能力。
|
||
|
||
### C. 首页和特殊入口绕过型
|
||
|
||
代表位置:
|
||
|
||
- `homeServiceImpl.py`
|
||
|
||
典型模式:
|
||
|
||
- `super_admin` 直接 `bypass_area`
|
||
|
||
问题本质:
|
||
|
||
- 首页入口可见性实际上也属于权限结果的一部分
|
||
- 不应长期依赖单角色绕过
|
||
|
||
### D. 业务规则附带角色语义型
|
||
|
||
代表位置:
|
||
|
||
- `contractTemplateServiceImpl.py`
|
||
|
||
典型模式:
|
||
|
||
- 只有“地区管理员”可上传模板
|
||
- 但实现仍由 `can_manage/is_global/is_area_admin` 这类角色派生结果承担
|
||
|
||
问题本质:
|
||
|
||
- 这是典型“业务域管理能力”
|
||
- 应转换成合同模板域显式权限,而不是继续绑死在 admin/provincial_admin 上
|
||
|
||
## 9.2 已确认的前端硬编码角色热点
|
||
|
||
### A. RAG 知识库管理 UI
|
||
|
||
代表位置:
|
||
|
||
- `components/dify-dataset-manager/index.tsx`
|
||
- `components/dify-dataset-manager/area-dataset-config.tsx`
|
||
- `hooks/use-area-dataset-config.ts`
|
||
|
||
典型模式:
|
||
|
||
- `provincial_admin` 可编辑全部
|
||
- `super_admin` 可编辑全部
|
||
- `admin` 仅可编辑本地区
|
||
- `canManageDataset = roleCanManageDataset || permissionBased`
|
||
|
||
问题本质:
|
||
|
||
- 当前前端同时混用了“角色白名单”和“权限点判断”
|
||
- 即使后端后续去角色化,前端 UI 仍会保留旧角色语义
|
||
|
||
### B. 路由 fallback 与角色映射
|
||
|
||
代表位置:
|
||
|
||
- `legal-platform-frontend/lib/auth/user-routes.ts`
|
||
- `legal-platform-frontend/lib/api/legacy/auth/user-routes.ts`
|
||
|
||
典型模式:
|
||
|
||
- `provincial_admin -> admin`
|
||
- `super_admin -> admin`
|
||
- `developer -> admin`
|
||
|
||
问题本质:
|
||
|
||
- 这是典型迁移兼容代码
|
||
- 如果长期保留,会把真实角色体系压扁成前端的少数桶位
|
||
|
||
### C. 页面 guard
|
||
|
||
代表位置:
|
||
|
||
- `legal-platform-frontend/lib/auth/guard.ts`
|
||
|
||
典型模式:
|
||
|
||
- `developer` 或 `provincial_admin` 才能进入某些设置页
|
||
|
||
问题本质:
|
||
|
||
- 这是明显的角色名授权
|
||
- 应改成 route/permission 授权,不应继续靠用户主角色字符串
|
||
|
||
### D. 特殊入口可见性辅助逻辑
|
||
|
||
代表位置:
|
||
|
||
- `legal-platform-frontend/lib/auth/cross-checking-access.ts`
|
||
|
||
典型模式:
|
||
|
||
- `provincial_admin` 自动加入“省局” area 候选
|
||
|
||
问题本质:
|
||
|
||
- 这类逻辑属于“前端对后端权限模型的二次解释”
|
||
- 如果保留过多,会持续制造边界分叉
|
||
|
||
## 9.3 为什么这些硬编码不能直接一刀删除
|
||
|
||
因为它们承担的职责并不相同。
|
||
|
||
### 第一类:可立即替换
|
||
|
||
- 服务层“动作白名单式”角色判断
|
||
- 例如 RAG 管理接口中的 `UserRole not in (...)`
|
||
|
||
这类逻辑可以优先替换为:
|
||
|
||
- 控制器层 permission 决策
|
||
- 服务层 scope/policy 决策
|
||
|
||
### 第二类:需先抽象再替换
|
||
|
||
- `is_global`
|
||
- `can_manage`
|
||
- `is_super_admin`
|
||
- `is_area_admin`
|
||
|
||
这些并不是最终目标,但当前很多模块都依赖它们构建 SQL 过滤条件。
|
||
|
||
因此正确做法不是直接删掉,而是先把它们提升为统一上下文派生结果:
|
||
|
||
- `ScopeContextProvider`
|
||
- `AdminCapabilityResolver`
|
||
|
||
之后再逐步把其实现从“角色硬编码”替换为“权限/能力决策”。
|
||
|
||
### 第三类:应保留为兼容层,但必须收缩边界
|
||
|
||
- 前端 role mapping
|
||
- fallback menu
|
||
- 部分特殊入口兼容逻辑
|
||
|
||
这些逻辑在迁移期可以保留,但必须:
|
||
|
||
1. 标记为兼容层
|
||
2. 只允许出现在前端适配层
|
||
3. 不允许继续扩散到服务层和新功能
|
||
|
||
## 9.4 推荐改造策略
|
||
|
||
### 第一阶段:建立统一能力派生层
|
||
|
||
新增统一能力对象,例如:
|
||
|
||
- `is_super_admin`
|
||
- `has_global_scope`
|
||
- `can_manage_area_resources`
|
||
- `can_manage_rbac`
|
||
- `can_manage_rag_dataset`
|
||
- `can_view_usage_stats`
|
||
|
||
这些字段应由:
|
||
|
||
- `roles`
|
||
- `permissions`
|
||
- `data_scope`
|
||
- 可选 `condition_filter`
|
||
|
||
综合解析,而不是仅看 `role_key`。
|
||
|
||
### 第二阶段:逐模块替换服务层角色直判
|
||
|
||
优先顺序建议:
|
||
|
||
1. `ragDatasetServiceImpl.py`
|
||
2. `rbacAdminServiceImpl.py`
|
||
3. `homeServiceImpl.py`
|
||
4. `contractTemplateServiceImpl.py`
|
||
5. 文档/公文/统计共用上下文派生
|
||
|
||
### 第三阶段:前端去角色化
|
||
|
||
前端改造原则:
|
||
|
||
1. UI 可见性优先使用 permission
|
||
2. 可编辑性使用后端返回的 capability 或 policy 结果
|
||
3. `user_role` 只保留展示和极少数兼容用途
|
||
4. 不再让前端自行推导“谁是管理员”
|
||
|
||
## 9.5 不同硬编码的替换目标
|
||
|
||
建议按下表理解:
|
||
|
||
- `super_admin` 全局绕过
|
||
替换为:`is_super_admin` capability,仅在极少数系统级接口保留
|
||
- `provincial_admin => is_global`
|
||
替换为:`effective_scope == ALL`
|
||
- `admin => can_manage`
|
||
替换为:领域型 manage permission + `effective_scope == DEPT`
|
||
- `common => self only`
|
||
替换为:`effective_scope == SELF`
|
||
- `provincial_admin/super_admin/admin` 共同白名单
|
||
替换为:某领域 `manage/create/update/delete` permission
|
||
|
||
这一步很关键,因为它把“角色名语义”拆成了“能力语义”。
|
||
|
||
---
|
||
|
||
## 10. 受影响接口与联动面分析
|
||
|
||
角色硬编码改造不会只影响几个 service,而会沿着“认证 -> 控制器 -> 服务层 -> 前端 UI -> 菜单/guard”整条链路传播。
|
||
|
||
因此必须提前识别影响面。
|
||
|
||
## 10.1 高影响后端接口组
|
||
|
||
### A. 文档模块
|
||
|
||
受影响接口包括但不限于:
|
||
|
||
- `POST /api/upload`
|
||
- `GET /api/documents/list`
|
||
- `GET /api/documents/status`
|
||
- `GET /api/documents/{DocumentId}`
|
||
- `GET /api/v3/review-points/{DocumentId}`
|
||
- `PATCH /api/v3/review-points/{ReviewPointResultId}/audit`
|
||
- `PATCH /api/v3/documents/{DocumentId}/confirm`
|
||
- `POST /api/documents/{DocumentId}/attachments`
|
||
- `PUT /api/documents/{DocumentId}`
|
||
- `DELETE /api/documents/{DocumentId}`
|
||
|
||
影响原因:
|
||
|
||
- 这些接口都依赖文档服务里的用户上下文派生和范围过滤
|
||
- 一旦 `is_global/can_manage` 计算方式改变,所有文档读写边界都会联动变化
|
||
|
||
### B. 公文模块
|
||
|
||
受影响接口包括但不限于:
|
||
|
||
- `POST /api/govdoc/documents`
|
||
- `GET /api/govdoc/documents`
|
||
- `GET /api/govdoc/documents/{documentId}`
|
||
- `PATCH /api/govdoc/documents/{documentId}`
|
||
- `DELETE /api/govdoc/documents/{documentId}`
|
||
- `POST /api/govdoc/runs`
|
||
- `GET /api/govdoc/runs/{runId}`
|
||
- `GET /api/govdoc/runs/{runId}/result`
|
||
- `GET /api/govdoc/runs/{runId}/findings`
|
||
- `GET /api/govdoc/runs/{runId}/entities`
|
||
- `GET /api/govdoc/runs/{runId}/structure`
|
||
- `GET /api/govdoc/runs/{runId}/outline`
|
||
- `GET /api/govdoc/runs/{runId}/paragraphs`
|
||
- `GET /api/govdoc/runs/{runId}/report/html`
|
||
- `GET /api/govdoc/runs/{runId}/report/docx`
|
||
- `GET /api/govdoc/documents/{documentId}/original`
|
||
|
||
影响原因:
|
||
|
||
- 公文模块沿用了与文档模块相似的范围控制模型
|
||
- run/result/report 等接口如果没有统一回挂到 document scope,容易出现“知道 runId 就能读结果”的风险
|
||
|
||
### C. 统计模块
|
||
|
||
受影响接口包括:
|
||
|
||
- `GET /api/v3/usage-stats/overview`
|
||
- `GET /api/v3/usage-stats/trends`
|
||
- `GET /api/v3/usage-stats/by-users`
|
||
- `GET /api/v3/usage-stats/by-departments`
|
||
- `GET /api/v3/usage-stats/by-areas`
|
||
- `GET /api/v3/usage-stats/details`
|
||
|
||
影响原因:
|
||
|
||
- 当前统计服务对“只有管理员可看”存在上下文派生逻辑
|
||
- 如果未来改成 permission 决策,统计域会是最先受影响的读接口集合之一
|
||
|
||
### D. RAG 模块
|
||
|
||
受影响接口包括:
|
||
|
||
- `GET /api/v3/rag/apps`
|
||
- `GET /api/v3/rag/apps/default`
|
||
- `GET /api/v3/rag/datasets/my`
|
||
- `GET /api/v3/rag/datasets/admin`
|
||
- `POST /api/v3/rag/datasets/admin`
|
||
- `PUT /api/v3/rag/datasets/admin/{DatasetId}`
|
||
- `DELETE /api/v3/rag/datasets/admin/{DatasetId}`
|
||
- `GET /api/v3/rag/datasets/{DatasetId}`
|
||
- `PATCH /api/v3/rag/datasets/{DatasetId}`
|
||
- 以及数据集文档、分段、检索测试等一系列 `/datasets/{DatasetId}/...` 接口
|
||
- `POST /api/v3/rag/chat/messages`
|
||
- 会话相关接口
|
||
|
||
影响原因:
|
||
|
||
- 控制器层已经按 permission 放行
|
||
- 服务层仍按 `UserRole` 二次限流
|
||
- 这是最典型的“双轨权限模型冲突”区域
|
||
|
||
### E. RBAC 管理模块
|
||
|
||
受影响接口包括:
|
||
|
||
- `GET /api/v3/rbac/roles`
|
||
- `POST /api/v3/rbac/roles`
|
||
- `PUT /api/v3/rbac/roles/{RoleId}`
|
||
- `DELETE /api/v3/rbac/roles/{RoleId}`
|
||
- `GET /api/v3/rbac/users`
|
||
- `GET /api/admin/users/organizations/tree`
|
||
- `GET /api/v3/rbac/roles/{RoleId}/users`
|
||
- `POST /api/v3/rbac/users/{UserId}/roles`
|
||
- `DELETE /api/v3/rbac/users/{UserId}/roles/{RoleId}`
|
||
- `GET /api/v3/rbac/users/{UserId}/roles`
|
||
- `GET /api/v3/routes`
|
||
- `GET/PUT /api/rbac/roles/{RoleId}/routes`
|
||
- `GET/POST /api/v3/rbac/role-permissions`
|
||
- `POST /api/v3/rbac/roles/{RoleId}/access`
|
||
- `GET /api/v3/routes/{RouteId}/permissions`
|
||
|
||
影响原因:
|
||
|
||
- 当前先 `_assertManagePermission`,再 `_assertPermission`
|
||
- 其中 `_assertManagePermission` 仍依赖角色派生 `can_manage`
|
||
- 未来若不调整,会出现“拥有 RBAC 写权限但不是 admin 角色”仍被拒绝的问题
|
||
|
||
### F. 首页入口模块
|
||
|
||
受影响接口:
|
||
|
||
- `GET /api/home/entry-modules`
|
||
|
||
影响原因:
|
||
|
||
- 首页可见入口当前含 `super_admin` 的 area bypass 语义
|
||
- 改动后会影响首页模块展示和交叉评查入口暴露范围
|
||
|
||
### G. 合同模板模块
|
||
|
||
受影响接口包括:
|
||
|
||
- `GET /api/v3/contract-templates/categories`
|
||
- `GET /api/v3/contract-templates`
|
||
- `POST /api/v3/contract-templates`
|
||
- `GET /api/v3/contract-templates/search`
|
||
- `GET /api/v3/contract-templates/{TemplateId}`
|
||
- `DELETE /api/v3/contract-templates/{TemplateId}`
|
||
|
||
影响原因:
|
||
|
||
- 业务文案和服务层逻辑都在强调“地区管理员才能上传”
|
||
- 这类业务域权限必须显式建模,否则角色去硬编码后会发生语义漂移
|
||
|
||
## 10.2 中影响后端接口组
|
||
|
||
### A. 交叉评查控制器
|
||
|
||
控制器层目前主要通过 permission 做功能准入,再由服务层按 task-member 关系控权。
|
||
|
||
受影响点:
|
||
|
||
- 若未来新增“交叉评查协调员”等角色
|
||
- 控制器层 permission、服务层关系权限、前端入口策略三者都要同步
|
||
|
||
### B. 评查点 / 评查点分组 / 规则配置
|
||
|
||
这些模块当前更多是 permission 驱动,但仍存在:
|
||
|
||
- OR 型 permission 校验
|
||
- 路由 fallback
|
||
- 某些 legacy 行为仍按旧角色认知理解的隐患
|
||
|
||
这类模块短期不一定要先改,但必须纳入联调验证范围。
|
||
|
||
## 10.3 前端受影响面
|
||
|
||
### A. 菜单与路由
|
||
|
||
受影响位置:
|
||
|
||
- `Sidebar.tsx`
|
||
- `user-routes.ts`
|
||
- `check-route-permission.ts`
|
||
- route fallback mapping
|
||
|
||
改造后可能出现的联动:
|
||
|
||
- 某些角色映射桶失效
|
||
- fallback 菜单与真实 route-permission 不一致
|
||
- 页面可见但接口被拒绝,或页面不可见但后端已授权
|
||
|
||
### B. 知识库管理相关页面
|
||
|
||
受影响位置:
|
||
|
||
- `components/dify-dataset-manager/*`
|
||
- `hooks/use-area-dataset-config.ts`
|
||
|
||
改造后必须改为:
|
||
|
||
- 以后端返回的 permission/capability 作为真相源
|
||
- 不能继续由前端自己判定“你是不是省级管理员”
|
||
|
||
### C. 页面 guard 和 session typing
|
||
|
||
受影响位置:
|
||
|
||
- `lib/auth/guard.ts`
|
||
- `lib/auth/session-user.ts`
|
||
- `lib/auth/jwt.ts`
|
||
|
||
改造重点:
|
||
|
||
- `user_role` 类型定义不能继续隐式代表完整能力模型
|
||
- guard 逻辑要逐步转成 permission 驱动
|
||
|
||
## 10.4 最容易遗漏的影响点
|
||
|
||
有 4 类点最容易在改造时被漏掉:
|
||
|
||
1. **服务层动作二次校验**
|
||
典型如 RAG:控制器已查 permission,但服务层又按角色拒绝
|
||
2. **只读接口的资源详情/下载接口**
|
||
典型如公文的 report/docx/original 下载
|
||
3. **首页和入口模块可见性**
|
||
这类功能通常不在权限改造 checklist 里,但实际也是访问控制
|
||
4. **前端本地缓存的 permission_map / user_role**
|
||
后端改完,前端缓存解释逻辑若不改,会出现脏权限体验
|
||
|
||
## 10.5 推荐联动改造顺序
|
||
|
||
为了降低波及风险,建议按下面顺序推进:
|
||
|
||
1. 先改后端统一决策层,不动前端行为
|
||
2. 接入 RAG 服务层,消除“permission 通过但角色名拒绝”的双轨冲突
|
||
3. 接入文档/公文/统计通用 scope
|
||
4. 接入 RBAC 管理域 `_assertManagePermission`
|
||
5. 接入首页入口与合同模板这类特殊管理域
|
||
6. 最后清理前端角色映射、UI 角色判断和 guard
|
||
|
||
这样可以避免一开始就同时触碰:
|
||
|
||
- 数据边界
|
||
- 功能权限
|
||
- 菜单展示
|
||
- 页面 guard
|
||
|
||
导致联调失控。
|
||
|
||
## 10.6 额外建议:建立“角色去硬编码回归清单”
|
||
|
||
建议在实际实施时,单独维护一份回归清单,至少覆盖:
|
||
|
||
- 某用户有 permission 但主角色不是 `admin/provincial_admin` 时,是否仍可正确访问
|
||
- 某用户被赋予新领域管理角色后,是否无需改代码即可生效
|
||
- 某用户菜单、按钮、接口、详情、下载、导出是否边界一致
|
||
- 前端是否仍存在基于 `user_role` 的旧判断把能力放大或缩小
|
||
|
||
---
|
||
|
||
## 11. 数据库迁移方案
|
||
|
||
## 9.1 第一阶段可不改表,仅改执行层
|
||
|
||
这是最推荐的路径。
|
||
|
||
先做:
|
||
|
||
- 新增决策服务
|
||
- 新增 scope resolver
|
||
- 新增 query builder
|
||
- 业务模块接入
|
||
|
||
在这一步,现有表足够使用。
|
||
|
||
## 9.2 第二阶段再做增强字段
|
||
|
||
若后续希望更强平台能力,再增量考虑:
|
||
|
||
- `permissions.scope_strategy`
|
||
- `permissions.resource_code`
|
||
- `permissions.policy_code`
|
||
- `role_permissions.scope_override_reason`
|
||
|
||
这些字段用于治理和解释,不是首批必要项。
|
||
|
||
## 9.3 数据迁移原则
|
||
|
||
1. 不删除旧字段
|
||
2. 不重命名核心字段
|
||
3. 先兼容运行,再切换调用方
|
||
4. 所有新增字段默认 nullable,避免一次性大面积回填风险
|
||
|
||
---
|
||
|
||
## 12. 渐进式实施路径
|
||
|
||
## 10.1 Phase 1:统一决策能力
|
||
|
||
目标:
|
||
|
||
- 先把平台底座搭好
|
||
|
||
交付:
|
||
|
||
- `PermissionDecisionService`
|
||
- `DataScopeResolver`
|
||
- `ScopeContextProvider`
|
||
- `QueryScopeBuilder`
|
||
|
||
收益:
|
||
|
||
- 新老模块都可开始接入
|
||
|
||
## 10.2 Phase 2:样板模块接入
|
||
|
||
建议顺序:
|
||
|
||
1. 文档
|
||
2. 公文
|
||
3. 统计
|
||
|
||
原因:
|
||
|
||
- 这三类模块已经有成熟范围逻辑
|
||
- 抽象收益最高
|
||
- 改造风险相对可控
|
||
|
||
## 10.3 Phase 3:菜单权限彻底数据库化
|
||
|
||
目标:
|
||
|
||
- 删除路由 fallback
|
||
- 删除静态菜单兼容
|
||
|
||
前提:
|
||
|
||
- 数据库路由集合补齐
|
||
- 权限点-route 映射完整
|
||
|
||
## 10.4 Phase 4:特殊模块治理
|
||
|
||
建议顺序:
|
||
|
||
1. RAG
|
||
2. 交叉评查
|
||
3. 评查点/规则/legacy 桥接模块
|
||
|
||
目标:
|
||
|
||
- 形成“通用 scope + 模块 policy”模式
|
||
|
||
## 10.5 Phase 5:治理与可观测性
|
||
|
||
补齐:
|
||
|
||
- 权限命中日志
|
||
- 越权拒绝原因
|
||
- 权限矩阵导出
|
||
- 自动化巡检任务
|
||
|
||
---
|
||
|
||
## 13. 测试与验收方案
|
||
|
||
## 11.1 必做测试矩阵
|
||
|
||
每个核心权限点至少覆盖以下用户组合:
|
||
|
||
- `super_admin`
|
||
- `provincial_admin`
|
||
- `admin`
|
||
- `common`
|
||
- 多角色用户
|
||
- 无 area 用户
|
||
- 被禁用用户
|
||
|
||
每个资源至少覆盖以下数据组合:
|
||
|
||
- 同地区数据
|
||
- 异地区数据
|
||
- 自己创建数据
|
||
- 他人创建数据
|
||
- 公共数据
|
||
- 关系型共享数据
|
||
|
||
## 11.2 必做接口验收
|
||
|
||
至少覆盖:
|
||
|
||
- 登录与 `/auth/me`
|
||
- 菜单获取
|
||
- 文档列表/详情/历史/删除
|
||
- 公文列表/详情
|
||
- 统计总览/趋势/明细
|
||
- RAG 应用/知识库
|
||
- 交叉评查任务/提案/投票
|
||
- RBAC 管理台
|
||
|
||
## 11.3 必做回归断言
|
||
|
||
1. 有 permission 但无 scope 不应越权看全量
|
||
2. 菜单可见不等于接口可调用,接口仍需后端鉴权
|
||
3. 仅知道资源 ID 不应绕过数据范围校验
|
||
4. 跨模块聚合查询不能扩大原始资源可见范围
|
||
5. `DENY` 必须稳定优先于 `GRANT`
|
||
|
||
## 11.4 建议增加自动化
|
||
|
||
建议建立:
|
||
|
||
- permission fixture
|
||
- user-role fixture
|
||
- region fixture
|
||
- resource ownership fixture
|
||
|
||
让权限测试不再依赖手工造数。
|
||
|
||
---
|
||
|
||
## 14. 风险与回滚方案
|
||
|
||
## 12.1 主要风险
|
||
|
||
1. 抽象过度,导致特殊模块被错误套入通用逻辑
|
||
2. 改造过程中菜单和接口权限短期不一致
|
||
3. scope 规则切换后产生历史行为变化
|
||
4. 多角色并集规则理解不一致,导致边界扩大或缩小
|
||
|
||
## 12.2 风险控制
|
||
|
||
1. 先在样板模块试点,不直接全量切
|
||
2. 新旧逻辑并行一段时间,输出对比日志
|
||
3. 为关键接口加“旧逻辑 vs 新逻辑” shadow compare
|
||
4. 管理台提供用户最终权限预览
|
||
|
||
## 12.3 回滚策略
|
||
|
||
1. 决策服务接入采用开关控制
|
||
2. 模块级按 feature flag 切换
|
||
3. 菜单 fallback 在数据库路由完全稳定前不删除
|
||
4. 新增字段不影响旧逻辑运行
|
||
|
||
---
|
||
|
||
## 15. 推荐实施排期
|
||
|
||
## 第 1 周
|
||
|
||
- 完成权限现状盘点和权限点清单冻结
|
||
- 设计 `PermissionDecisionService` 和 `DataScopeResolver`
|
||
- 输出统一 scope 规则说明
|
||
|
||
## 第 2 周
|
||
|
||
- 落地统一决策与查询构建器
|
||
- 接入文档模块
|
||
- 建立第一批自动化权限测试
|
||
|
||
## 第 3 周
|
||
|
||
- 接入公文与统计模块
|
||
- 补齐管理台权限预览能力
|
||
- 开始新旧逻辑对比日志
|
||
|
||
## 第 4 周
|
||
|
||
- 接入 RAG
|
||
- 梳理交叉评查 policy
|
||
- 补齐数据库路由集合
|
||
|
||
## 第 5 周
|
||
|
||
- 切换菜单只走数据库路由
|
||
- 处理 legacy 规则/评查点模块
|
||
- 清理前端 fallback
|
||
|
||
## 第 6 周
|
||
|
||
- 全量回归
|
||
- 安全测试
|
||
- 观察期与灰度发布
|
||
|
||
---
|
||
|
||
## 16. 最终推荐方案
|
||
|
||
如果只给出一条最重要的改造主线,我的建议是:
|
||
|
||
**不要推翻现有 RBAC 结构,优先补齐统一的数据范围执行平台。**
|
||
|
||
更具体地说,正确的改造顺序应该是:
|
||
|
||
1. 先保留现有 `sso_users/roles/permissions/routes` 模型
|
||
2. 把 `data_scope` 从“设计字段”变成“统一可执行能力”
|
||
3. 把文档、公文、统计里的重复数据范围逻辑抽成平台底座
|
||
4. 把 RAG、交叉评查这类特殊模块归入独立 policy,而不是粗暴并表
|
||
5. 最后再清理菜单 fallback 和角色硬编码
|
||
|
||
这样做的收益最大:
|
||
|
||
- 改造风险最低
|
||
- 与现有代码最兼容
|
||
- 能最快提升一致性和安全性
|
||
- 能为后续模块扩展提供稳定底座
|
||
|
||
---
|
||
|
||
## 17. 建议立项清单
|
||
|
||
建议把后续工作拆成 8 个明确任务:
|
||
|
||
1. 建立权限决策对象与统一接口
|
||
2. 实现 data_scope 解析器
|
||
3. 实现通用查询 scope builder
|
||
4. 文档模块接入统一 scope
|
||
5. 公文与统计模块接入统一 scope
|
||
6. RAG / 交叉评查 policy 化
|
||
7. 数据库路由补齐并移除 fallback
|
||
8. 建立权限可观测性与自动化测试矩阵
|
||
|
||
这 8 项完成后,当前项目的角色权限架构就会从“可用但分散”,升级为“稳定、统一、可治理、可演进”的平台化体系。
|