11 KiB
11 KiB
角色去硬编码迁移清单
适用范围:当前项目中所有直接依赖
super_admin/provincial_admin/admin/common/developer的权限判断
文档定位:从“问题分析”进入“逐文件迁移清单”,指导研发按优先级拆改。
1. 迁移目标
本清单的目标不是把所有“角色”这个概念删掉,而是把“用角色名直接判断能力”的写法替换成下面三类正规来源:
permission_keyeffective_scopemodule policy / capability snapshot
保留角色本身作为“授权载体”,但不再让角色名直接主导业务逻辑。
2. 问题类型定义
为方便排期,先统一问题类型。
| 类型 | 含义 |
|---|---|
CTX |
服务层上下文派生硬编码 |
ACT |
服务层动作放行硬编码 |
UI |
前端按钮/编辑态硬编码 |
GUARD |
前端路由、guard、fallback、role mapping 硬编码 |
COMPAT |
兼容层短期保留但必须收缩的旧逻辑 |
3. 后端迁移清单
3.1 P0:必须最先处理
| 文件 | 当前写法 | 问题类型 | 替换目标 | 优先级 | 风险 | 影响范围 |
|---|---|---|---|---|---|---|
fastapi_modules/fastapi_leaudit/services/impl/ragDatasetServiceImpl.py |
多处 UserRole in ('provincial_admin','admin','super_admin') |
ACT |
改为 rag:* permission + RagPolicy + effective_scope |
P0 |
高 | RAG 管理接口、数据集文档接口 |
fastapi_modules/fastapi_leaudit/services/impl/ragChatServiceImpl.py |
user_role == 'provincial_admin'、_app_visible 角色分支 |
ACT |
改为 PUBLIC_MIXED 策略 |
P0 |
高 | 应用列表、默认应用、聊天入口 |
fastapi_modules/fastapi_leaudit/controllers/ragChatController.py |
把 UserRole 透传给 service |
ACT |
改为透传 ScopeContext/CapabilitySnapshot |
P0 |
中 | 所有 RAG 接口联动 |
3.2 P1:统一上下文能力层
| 文件 | 当前写法 | 问题类型 | 替换目标 | 优先级 | 风险 | 影响范围 |
|---|---|---|---|---|---|---|
fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py |
_getCurrentUserContext() 中按 role_key IN (...) 生成 is_global/can_manage/is_super_admin |
CTX |
改为 PermissionDecisionService |
P1 |
高 | 文档列表、详情、附件、确认、删除 |
fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py |
通过 is_global/can_manage 控制 region/created_by |
CTX |
改为 GovdocPolicy |
P1 |
高 | 公文详情、run、报告、下载 |
fastapi_modules/fastapi_leaudit/services/impl/usageStatsServiceImpl.py |
_getCurrentUserContext 中 role_key IN (...) 派生范围 |
CTX |
改为 UsageStatsPolicy |
P1 |
中高 | 概览、趋势、明细 |
fastapi_modules/fastapi_leaudit/services/impl/contractTemplateServiceImpl.py |
is_global/can_manage/is_area_admin 依赖角色名 |
CTX |
改为 ContractTemplatePolicy |
P1 |
中 | 模板列表、搜索、创建、删除 |
fastapi_modules/fastapi_leaudit/services/impl/rbacAdminServiceImpl.py |
bool_or(r.role_key IN (...)) 派生管理能力 |
CTX |
改为 RbacAdminPolicy + rbac permission |
P1 |
高 | 用户列表、组织树、角色分配 |
fastapi_modules/fastapi_leaudit/services/impl/homeServiceImpl.py |
role_key = 'super_admin' => bypass_area |
CTX |
改为首页能力快照 | P1 |
中 | 首页入口可见性 |
3.3 P2:默认角色与兼容角色清理
| 文件 | 当前写法 | 问题类型 | 替换目标 | 优先级 | 风险 | 影响范围 |
|---|---|---|---|---|---|---|
fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py |
用户无角色时自动补 common;回退主角色 common |
COMPAT |
保留默认角色机制,但从业务能力判断中剥离“common 特权假设” | P2 |
中 | 登录、初始化用户 |
fastapi_modules/fastapi_leaudit/services/impl/rbacServiceImpl.py |
roleBucket = "admin" if any(role in {...}) else "common" |
COMPAT |
仅短期保留在菜单兼容层,逐步删除角色桶映射 | P2 |
高 | 路由树、菜单 fallback |
fastapi_modules/fastapi_leaudit/services/impl/rbacServiceImpl.py |
静态蓝图 _COMPAT_ROUTE_BLUEPRINTS 以 admin/common 分桶 |
COMPAT |
改为数据库路由兜底,不认角色桶 | P2 |
中高 | 前端菜单 |
4. 前端迁移清单
4.1 P0:直接影响权限感知
| 文件 | 当前写法 | 问题类型 | 替换目标 | 优先级 | 风险 | 影响范围 |
|---|---|---|---|---|---|---|
legal-platform-frontend/components/dify-dataset-manager/index.tsx |
provincial_admin/super_admin/admin 决定 canEditDataset |
UI |
改为读 rag 能力或 permission_map |
P0 |
高 | RAG 编辑按钮、详情编辑态 |
legal-platform-frontend/hooks/use-area-dataset-config.ts |
roleCanManageDataset = provincial_admin/super_admin/admin |
UI |
改为纯 permission 决策 | P0 |
高 | 知识库配置页全部操作 |
legal-platform-frontend/components/dify-dataset-manager/area-dataset-config.tsx |
isProvincialAdmin、非省级自动填地区 |
UI |
改为根据 effective_scope 与 allowed_areas 决定 |
P0 |
中高 | 地区选择器、创建编辑表单 |
4.2 P1:菜单与路由层
| 文件 | 当前写法 | 问题类型 | 替换目标 | 优先级 | 风险 | 影响范围 |
|---|---|---|---|---|---|---|
legal-platform-frontend/lib/auth/user-routes.ts |
静态 FALLBACK_MENU_DATA.admin/common |
GUARD |
收敛为数据库路由兜底,不做角色桶映射 | P1 |
高 | 主菜单 |
legal-platform-frontend/lib/api/legacy/auth/user-routes.ts |
mapUserRoleToRoleKey() 中 provincial_admin -> admin、developer -> admin |
GUARD |
删除角色映射,直接使用后端返回路由与权限 | P1 |
高 | 菜单缓存、路由授权 |
legal-platform-frontend/components/layout/Sidebar.tsx |
按 userRole 拉路由、写 localStorage.user_role |
GUARD |
改为按登录态和后端返回能力渲染 | P1 |
中高 | 侧边栏菜单、权限 map |
legal-platform-frontend/lib/auth/cross-checking-access.ts |
provincial_admin 自动补 省局 area 候选 |
GUARD |
改为服务端返回 allowed_areas |
P1 |
中 | 交叉评查入口展示 |
legal-platform-frontend/lib/auth/guard.ts |
developer/provincial_admin 白名单进入设置页 |
GUARD |
改为检查后台管理权限 | P1 |
高 | 设置页访问 |
4.3 P2:页面级残留
| 文件 | 当前写法 | 问题类型 | 替换目标 | 优先级 | 风险 | 影响范围 |
|---|---|---|---|---|---|---|
legal-platform-frontend/app/(audit)/contract-template/list/ContractTemplateListClient.tsx |
currentUser.role === "admin" 才能上传 |
UI |
改为 contract_template:create:write |
P2 |
中高 | 合同模板上传入口 |
legal-platform-frontend/app/(audit)/role-permissions/RolePermissionsClient.tsx |
provincial_admin 禁删、coreRoles = ['provincial_admin','admin','common']、setIsCityAdmin(userRole==='admin') |
UI/COMPAT |
保留系统角色保护逻辑,但与角色名硬编码解耦 | P2 |
中高 | 角色权限管理页 |
legal-platform-frontend/hooks/usePermission.tsx |
默认 userRole = common,大量消费 localStorage.user_role |
COMPAT |
保留兼容字段,但新增能力快照来源,逐步弱化角色中心地位 | P2 |
中 | 多页面基础权限钩子 |
legal-platform-frontend/components/layout/Layout.tsx |
默认 userRole = developer,回退读取本地角色 |
COMPAT |
改为显式会话能力初始化 | P2 |
中 | 全局布局 |
5. 接口影响面清单
角色去硬编码不会只影响代码写法,还会影响接口行为。
5.1 后端接口影响
| 模块 | 受影响接口 |
|---|---|
| RAG | /v3/rag/apps、/v3/rag/apps/default、/v3/rag/datasets/admin*、/v3/rag/datasets/{id}* |
| 文档 | /documents/list、/documents/{id}、/documents/status、/v3/review-points/* |
| 公文 | /govdoc/documents*、/govdoc/runs/*、/govdoc/documents/{id}/original |
| 统计 | /v3/usage-stats/* |
| RBAC | /v3/rbac/users*、/v3/rbac/roles/{id}/users、/v3/rbac/users/{id}/roles* |
| 合同模板 | /v3/contract-templates* |
| 首页 | 首页入口模块加载逻辑 |
5.2 前端受影响页面
| 页面/模块 | 受影响点 |
|---|---|
| 侧边栏菜单 | 路由来源、权限 map 来源 |
| 知识库管理页 | 可编辑、可创建、地区选择范围 |
| 合同模板页 | 上传按钮、删除按钮 |
| 设置页 | 进入 guard |
| 交叉评查入口 | 是否显示入口模块 |
| 角色权限管理页 | 系统角色保护、核心角色展示逻辑 |
6. 推荐替换模式
6.1 后端替换模式
不推荐:
if user_role in ("provincial_admin", "admin", "super_admin"):
...
推荐:
decision = await permissionDecisionService.decide(
ScopeContext(
user_id=current_user_id,
permission_key="rag:dataset:update",
module="rag",
resource_id=dataset_id,
)
)
if not decision.allowed:
raise Forbidden()
6.2 前端替换模式
不推荐:
const canUpload = currentUser.role === "admin";
推荐:
const canUpload = hasPermission("contract_template:create:write");
或者:
const canManageDataset = capability.rag?.manage === true;
7. 兼容策略
并不是所有角色相关代码都要同一天删除。
建议分 3 类处理:
立即删除- 服务层动作白名单
- 前端页面按钮直接按角色判断
先替换后删除is_global/can_manage/bypass_area
短期保留但冻结- 路由 fallback
- 本地
user_role兼容字段
“冻结”的意思是:
- 不再新增依赖
- 只允许向统一能力来源迁移
8. 风险说明
8.1 最大风险
如果只改后端,不改前端,会出现:
- 后端已经可用,但前端按钮还不显示
- 菜单还按旧角色展示
- 用户误以为权限失效
如果只改前端,不改后端,会出现:
- 前端展示放开
- 后端仍按旧角色拒绝
- 联调体验极差
8.2 第二风险
去硬编码后,如果没有统一能力快照,前端容易又发明一套新的本地推断规则。
所以必须同步提供:
/auth/me扩展能力- 或专门的当前用户能力接口
9. 推荐执行顺序
建议按下面顺序推进:
ragDatasetServiceImpl.pyragChatServiceImpl.py- RAG 前端 3 个文件
documentServiceImpl.pygovdocServiceImpl.pyusageStatsServiceImpl.pyrbacAdminServiceImpl.pycontractTemplateServiceImpl.pyhomeServiceImpl.py- 菜单/guard/fallback 前端文件
原因:
- 先打掉最明显的双轨冲突
- 再统一高风险数据域
- 最后收口前端兼容层
10. 完成判定
角色去硬编码完成,不是指仓库里再也没有 admin 字符串,而是指:
- 角色名不再直接决定业务动作是否允许
- 角色名不再直接决定数据边界
- 前端不再用角色名推断核心按钮与菜单
- 新增自定义角色时,不需要全仓库搜角色名改逻辑
只有达到这 4 条,才算真正完成迁移。