Files

11 KiB

角色去硬编码迁移清单

适用范围:当前项目中所有直接依赖 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 _getCurrentUserContextrole_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_BLUEPRINTSadmin/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_scopeallowed_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 -> admindeveloper -> 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 类处理:

  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 条,才算真正完成迁移。