# 角色去硬编码迁移清单 > 适用范围:当前项目中所有直接依赖 `super_admin/provincial_admin/admin/common/developer` 的权限判断 > 文档定位:从“问题分析”进入“逐文件迁移清单”,指导研发按优先级拆改。 --- ## 1. 迁移目标 本清单的目标不是把所有“角色”这个概念删掉,而是把“用角色名直接判断能力”的写法替换成下面三类正规来源: 1. `permission_key` 2. `effective_scope` 3. `module 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 后端替换模式 不推荐: ```python if user_role in ("provincial_admin", "admin", "super_admin"): ... ``` 推荐: ```python 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 前端替换模式 不推荐: ```ts const canUpload = currentUser.role === "admin"; ``` 推荐: ```ts const canUpload = hasPermission("contract_template:create:write"); ``` 或者: ```ts const canManageDataset = capability.rag?.manage === true; ``` --- ## 7. 兼容策略 并不是所有角色相关代码都要同一天删除。 建议分 3 类处理: 1. `立即删除` - 服务层动作白名单 - 前端页面按钮直接按角色判断 2. `先替换后删除` - `is_global/can_manage/bypass_area` 3. `短期保留但冻结` - 路由 fallback - 本地 `user_role` 兼容字段 “冻结”的意思是: - 不再新增依赖 - 只允许向统一能力来源迁移 --- ## 8. 风险说明 ## 8.1 最大风险 如果只改后端,不改前端,会出现: - 后端已经可用,但前端按钮还不显示 - 菜单还按旧角色展示 - 用户误以为权限失效 如果只改前端,不改后端,会出现: - 前端展示放开 - 后端仍按旧角色拒绝 - 联调体验极差 ## 8.2 第二风险 去硬编码后,如果没有统一能力快照,前端容易又发明一套新的本地推断规则。 所以必须同步提供: - `/auth/me` 扩展能力 - 或专门的当前用户能力接口 --- ## 9. 推荐执行顺序 建议按下面顺序推进: 1. `ragDatasetServiceImpl.py` 2. `ragChatServiceImpl.py` 3. RAG 前端 3 个文件 4. `documentServiceImpl.py` 5. `govdocServiceImpl.py` 6. `usageStatsServiceImpl.py` 7. `rbacAdminServiceImpl.py` 8. `contractTemplateServiceImpl.py` 9. `homeServiceImpl.py` 10. 菜单/guard/fallback 前端文件 原因: - 先打掉最明显的双轨冲突 - 再统一高风险数据域 - 最后收口前端兼容层 --- ## 10. 完成判定 角色去硬编码完成,不是指仓库里再也没有 `admin` 字符串,而是指: 1. 角色名不再直接决定业务动作是否允许 2. 角色名不再直接决定数据边界 3. 前端不再用角色名推断核心按钮与菜单 4. 新增自定义角色时,不需要全仓库搜角色名改逻辑 只有达到这 4 条,才算真正完成迁移。