Files
leaudit-platform-backend/docs/用户权限开发TaskList.md
T
2026-04-29 15:23:19 +08:00

879 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 用户权限开发 TaskList
> 目标:在 `leaudit-platform` 里,基于当前真实业务落地一套 **单地区隔离 + 角色权限 + 数据范围控制** 的用户体系,并能把老系统用户数据平滑迁移过来。
这份文档不是泛泛设计稿,而是后续开发的执行清单。
---
## 1. 当前结论先说清楚
当前这条线,应该按下面原则做,不要再发散:
- 用户地区只认 `sso_users.area`
- 数据隔离只做单地区,不做多地区授权
- 当前业务角色只保留:
- `provincial_admin`
- `admin`
- `common`
- `super_admin` 只作为可选系统维护角色
- 数据范围只保留:
- `ALL`
- `DEPT`
- `SELF`
- 新系统要兼容老系统已有数据结构,不要为了“理论优雅”把老数据迁移难度抬高
---
## 2. 当前新系统现状盘点
## 2.0 本次实际检查结果(2026-04-29
我已经实际检查了当前 `leaudit_platform` 新库和老库 `docauditai`,结论如下:
- 新库 `leaudit_platform` 原先 **完全没有** 这 7 张核心 RBAC 表:
- `sso_users`
- `roles`
- `user_role`
- `permissions`
- `role_permissions`
- `sys_routes`
- `role_route`
- 新库现阶段只有 `leaudit_*` 业务表,所以原有认证/权限代码其实处于“代码已写、库表未落地”的状态
- 我已经补了可执行 SQL
- `scripts/user_rbac_schema_patch.sql`
- `scripts/user_rbac_seed.sql`
- `scripts/user_rbac_migration_audit.sql`
- 我已经把 `schema_patch + seed` 执行进当前新库
- 当前新库 RBAC 初始化结果:
- `roles = 4`
- `permissions = 30`
- `role_permissions = 90`
- `sys_routes = 9`
- `role_route = 30`
- `sso_users = 0`
- `user_role = 0`
老库 `docauditai` 的迁移审计关键结果:
- `sso_users = 4106`
- `roles = 3`
- `user_role = 11`
- `permissions = 133`
- `role_permissions = 222`
- `sys_routes = 34`
- `role_route = 95`
- 老库 **没有空地区、没有重复 sub、没有重复 username**
- 老库 **4106 个用户里有 4098 个没有角色**
- 老库真实角色分布非常集中:
- `common = 6`
- `admin = 4`
- `provincial_admin = 1`
这说明:
- 老系统用户登录主数据是可迁的
- 但角色并不是“每个用户都显式分配了 user_role”
- 新系统迁移时必须补一轮“默认角色落地策略”,不能只机械复制 `user_role`
## 2.1 已有能力
当前新系统已经有这些基础:
- 已有 `sso_users` 登录查询逻辑
- 已有 JWT 签发与鉴权
- 已有 `user_role / roles / role_permissions / permissions` 的查询代码雏形
- 已有受保护路由统一挂载 JWT 依赖:`fastapi_modules/fastapi_leaudit/controllers/__init__.py`
- 已有认证入口:`/auth/login``/auth/password_login`
## 2.2 当前实际代码路径
当前这条线的核心代码在:
- `fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py`
- `fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py`
- `fastapi_common/fastapi_common_security/jwtService.py`
- `fastapi_common/fastapi_common_security/security.py`
- `fastapi_modules/fastapi_leaudit/controllers/auth/authController.py`
## 2.3 当前最关键的问题
### 问题 1:权限设计文档和实际代码字段名不一致
当前代码查的是:
- `roles.role_key`
- `permissions.permission_key`
- `role_permissions.grant_type`
但我前面新写的初始化 SQL 用的是:
- `roles.role_name`
- `permissions.permission_code`
这说明:
- **现阶段不能直接执行那份初始化 SQL 到现有库**
- 必须先按当前实际数据库字段重新收一版正式建表/初始化方案
### 问题 2:登录后只取“一个角色”
当前 `authServiceImpl.py` 里:
```python
SELECT r.role_key ... LIMIT 1
```
这意味着:
- 多角色用户会被截断成单角色
- JWT 中的 `roles` 没真正使用起来
- 后续 `ALL > DEPT > SELF` 的数据范围收敛逻辑无法成立
### 问题 3:JWT 里没有真正放入完整权限集
当前 JWT 虽然支持 `roles` 字段,但登录时只传了:
- `userRole`
- `area`
没有把:
- 全量角色列表
- 权限点列表
- 最终数据范围摘要
稳定打进去。
这会导致:
- `/me` 接口还不完整
- 前端拿不到统一用户权限视图
- 后端每次都要重新查库,且现有逻辑并未闭环
### 问题 4:当前没有统一的数据范围注入层
现在只是“能查角色 / 权限”,但还没有真正统一实现:
- 文档列表自动按 `area` 过滤
- 用户列表自动按 `area` 过滤
- 评查 run / result 自动按文档归属校验
也就是说:
- **功能权限雏形有了,数据权限还没有真正落地**
### 问题 5OAuth 登录仍然可能把 area 当外部输入覆盖
当前 OAuth 登录里:
- `Area=requestData.get("area")`
- 然后直接 `UPDATE sso_users SET ... area = :area`
这是很危险的。
因为这意味着:
- 前端或调用方传什么 area,就可能把用户地区改掉
- 数据隔离基础字段可能被外部请求污染
后续必须改成:
- area 只能来自后台可信源
- 登录请求不能直接覆盖 area
### 问题 6:新用户自动创建后没有默认角色闭环
当前 OAuth 首登自动插入 `sso_users`,但代码里没有看到紧接着分配默认 `common` 角色的闭环。
风险:
- 新用户建出来了,但没有角色
- 没角色则权限查询为空
- 前端表现为“登录成功但啥也看不到”
### 问题 7:密码仍然是明文比对
当前 `PasswordLogin()` 里:
- 直接 `user.get("password") != Password`
这是明显安全风险。
即使当前先沿用旧系统,也至少要在 tasklist 里明确:
- 第一阶段兼容旧明文
- 第二阶段升级为哈希存储与校验
### 问题 8:缺少统一的 `/api/auth/me`
当前文档里已经定义了 `/api/auth/me`,但现有 controller 里还没有真正落地。
这会影响:
- 前端初始化用户态
- 角色/权限/地区统一回显
- 登录后刷新恢复
---
## 3. 老系统可迁移数据结论
基于老项目 `docauditai` 的数据库快照和代码分析,当前可直接继承的核心表是:
- `sso_users`
- `roles`
- `user_role`
- `permissions`
- `role_permissions`
- `sys_routes`
- `role_route`
## 3.1 老系统 `sso_users` 关键字段
老系统 `sso_users` 目前至少包含:
- `id`
- `sub`
- `username`
- `nick_name`
- `phone_number`
- `email`
- `ou_id`
- `ou_name`
- `status`
- `is_leader`
- `password`
- `try_count`
- `try_login_time`
- `area`
- `tenant_name`
- `dep_short_name`
- `dep_name`
- `mq_person_uuid`
- `mq_account_uuid`
- `mq_synced_at`
- `created_at`
- `updated_at`
- `deleted_at`
### 迁移判断
这说明:
- 新系统**完全没必要重新发明用户主表**
- 最优方案是:
- 继续沿用 `sso_users`
- 补必要索引/约束/注释
- 修正其业务语义
## 3.2 老系统 `roles` 关键字段
老系统 `roles` 目前至少包含:
- `id`
- `role_key`
- `role_name`
- `data_scope`
- `description`
- `parent_role_id`
- `priority`
- `is_system_role`
- `permissions_cache`
- `metadata`
- `created_at`
- `updated_at`
### 迁移判断
建议:
- 保留 `role_key` 作为机器标识
- 保留 `role_name` 作为中文/展示名
- 继续使用 `data_scope`
- `parent_role_id / permissions_cache / metadata` 可以先保留但不作为第一阶段核心依赖
## 3.3 老系统 `permissions` 关键字段
老系统 `permissions` 目前至少包含:
- `id`
- `permission_key`
- `module`
- `resource`
- `action`
- `description`
- `display_name`
- `permission_type`
- `is_system`
- `metadata`
- `parent_id`
- `sort_order`
- `route_id`
- `api_path`
- `api_method`
- `created_at`
- `updated_at`
### 迁移判断
建议:
- 不要再新造 `permission_code`
- 直接沿用 `permission_key`
- 后续新系统全部按 `permission_key` 统一
## 3.4 老系统 `role_permissions` 关键字段
老系统 `role_permissions` 目前至少包含:
- `role_id`
- `permission_id`
- `grant_type`
- `data_scope`
- `condition_filter`
- `metadata`
- `created_at`
- `updated_at`
### 迁移判断
建议:
- 继续保留 `grant_type`
- 第一阶段只用 `GRANT`
- `DENY` 能力先兼容不扩展
- `condition_filter` 暂不作为第一阶段核心能力
---
## 4. 最终推荐表结构策略
这里不是从零建库,而是:
- **以老系统实际表结构为准**
- 对新系统补齐缺失字段、索引、语义约束
- 避免再造第二套平行用户权限模型
## 4.1 `sso_users` 目标策略
### 保留字段
- 保留老系统现有字段不动
- 核心业务字段继续认:`area`
### 必须加的约束 / 索引
建议检查并补:
- `UNIQUE(sub)`
- `INDEX(area)`
- `INDEX(status)`
- `INDEX(deleted_at)`
- `INDEX(username)`
### 字段语义正式化
- `sub`:统一身份唯一标识
- `username`:登录名 / 工号 / 展示账号
- `nick_name`:真实姓名
- `area`:用户主地区,也是默认数据隔离依据
- `password`:短期兼容旧值,后续迁移为哈希
## 4.2 `roles` 目标策略
继续沿用:
- `role_key`:机器标识,例如 `provincial_admin`
- `role_name`:中文展示名,例如“省级管理员”
- `data_scope`:默认数据范围
建议正式保留的角色:
- `provincial_admin`
- `admin`
- `common`
- `super_admin`(可选)
## 4.3 `permissions` 目标策略
继续沿用:
- `permission_key`
- `api_path`
- `api_method`
- `route_id`
建议后续所有新权限都按下面格式命名:
- `auth:me:read`
- `documents:list:read`
- `documents:upload:write`
- `audit:run:execute`
- `rules:binding:update`
不要混用:
- 一部分 `documents.list`
- 一部分 `document:read:all`
必须统一成一种风格。
### 我建议
直接收口成老系统已有风格:
- `module:resource:action`
这样能和老数据完全对齐。
## 4.4 `role_permissions` 目标策略
继续沿用:
- `grant_type`
- `data_scope`
建议唯一约束明确为:
- `(role_id, permission_id, grant_type, data_scope)`
但在第一阶段实际配置时:
- 尽量只放 `GRANT`
- `data_scope` 按权限点是否涉及数据决定
## 4.5 `user_role` 目标策略
继续沿用现有结构即可。
关键点不是表结构,而是后端逻辑必须支持:
- 一个用户可以挂多个角色
- 登录时不能 `LIMIT 1`
- 权限汇总和数据范围要支持多角色收敛
## 4.6 `sys_routes / role_route` 目标策略
继续沿用旧系统结构即可。
重点是:
- 前端菜单权限可以继续从这里出
-**接口权限不能只依赖菜单权限**
- API 权限必须还是走 `permissions / role_permissions`
---
## 5. 当前逻辑漏洞清单(必须按优先级修)
## P0:必须先修
### 5.1 角色/权限字段命名统一
要统一到底使用:
- `role_key` 还是 `role_name`
- `permission_key` 还是 `permission_code`
当前结论:
- 统一用 `role_key`
- 统一用 `permission_key`
### 5.2 登录角色查询改成多角色
当前:
- `LIMIT 1`
必须改成:
- 查询全部角色
- JWT 带 `roles`
- 兼容保留一个 `user_role` 主角色字段给旧前端
### 5.3 OAuth 登录禁止直接覆盖 `area`
必须改成:
- 登录入参中的 `area` 不再直接写库
- area 只能来自:
- 老库已存在值
- 后台管理维护
- 后续可信组织同步
### 5.4 新用户自动分配默认角色
OAuth 首登新用户创建后,必须补:
- 自动赋 `common`
### 5.5 `/api/auth/me` 落地
要把当前用户的:
- 基本信息
- `area`
- `roles`
- `permissions`
统一返回。
## P1:第二阶段紧跟着修
### 5.6 数据范围注入
至少要先覆盖:
- 文档列表
- 文档详情
- 用户列表
- 评查状态 / 结果
### 5.7 密码校验升级
短期兼容旧明文,长期迁移到哈希:
- 登录时支持“旧明文兼容 + 新哈希优先”
- 用户下次修改密码时写入哈希
### 5.8 权限缓存 / 权限聚合
后续可以考虑:
- JWT 轻载
- 服务端缓存权限聚合结果
但这不是 P0。
---
## 6. 老系统用户数据迁移策略
## 6.1 迁移原则
不是“把老用户复制一份到新表”,而是:
- **尽可能复用原表结构**
- 用增量清洗 + 角色校正 + 地区校正的方式迁移
## 6.2 迁移对象
第一阶段只迁这几类数据:
1. `sso_users`
2. `roles`
3. `user_role`
4. `permissions`
5. `role_permissions`
6. `sys_routes`
7. `role_route`
## 6.3 `sso_users` 迁移规则
### 必迁字段
- `id`
- `sub`
- `username`
- `nick_name`
- `phone_number`
- `email`
- `ou_id`
- `ou_name`
- `status`
- `is_leader`
- `password`
- `area`
- `tenant_name`
- `dep_name`
- `dep_short_name`
- `created_at`
- `updated_at`
- `deleted_at`
### 可选迁字段
- `mq_person_uuid`
- `mq_account_uuid`
- `mq_synced_at`
- `try_count`
- `try_login_time`
### 迁移前校验
要先出统计:
- `sub` 是否有重复
- `username` 是否有重复
- `area` 是否为空
- `status != 0` 的禁用用户数量
- `deleted_at is not null` 的软删除用户数量
## 6.4 角色映射规则
要先梳理老库中真实 `role_key` 分布。
预期映射:
- `provincial_admin` → 保留
- `admin` → 保留
- `common` → 保留
- 其他历史角色:
- 先做映射表
- 无法归类的先落到 `common`
- 再人工复核
### 明确不再延续的角色
- `city_admin`
- `review_manager`
- `review_user`
- `rule_admin`
如果老库真的还残留这些历史角色,不建议直接带入新系统业务角色定义,应该做映射清洗。
## 6.5 area 清洗规则
迁移前要先把 `sso_users.area` 跑一遍质量检查:
- 是否为空
- 是否存在历史别名
- 是否存在前后空格
- 是否存在同义不同写法
最后要统一成一套稳定值,例如:
- `省局`
- `梅州`
- `云浮`
- `揭阳`
- `潮州`
---
## 7. 开发分阶段 TaskList
下面是正式开发顺序。
## 阶段 A:数据库基线收口
### A1. 先核对当前库真实表结构
目标:
- 以当前数据库真实字段为准
- 不再拿“理想 SQL”直接执行
动作:
- 检查 `sso_users`
- 检查 `roles`
- 检查 `user_role`
- 检查 `permissions`
- 检查 `role_permissions`
- 检查 `sys_routes`
- 检查 `role_route`
产出:
- 一份“现网真实表结构快照”
- 一份“目标结构差异清单”
### A2. 出正式迁移 SQL
目标:
- 不是重建表
- 是补字段 / 补索引 / 补约束 / 补初始化数据
动作:
- 修正角色初始化 SQL
- 修正权限初始化 SQL
- 修正菜单初始化 SQL
- 统一全部字段名到现有真实库
产出:
- `用户权限_schema_patch.sql`
- `用户权限_seed.sql`
## 阶段 B:登录与 JWT 收口
### B1. 修 `AuthServiceImpl`
必须改:
- 多角色查询
- 新用户默认角色分配
- OAuth 登录禁止外部覆盖 `area`
- 登录响应统一返回 `roles`
- 兼容返回单个 `user_role`
### B2. 修 `JwtService`
必须改:
- token 中写入 `roles`
- 保留 `user_role`
- 写入 `area`
- 视情况写入精简 `permissions`
### B3. 新增 `/api/auth/me`
返回:
- 用户基本信息
- area
- roles
- permissions
## 阶段 C:权限聚合与数据范围引擎
### C1. 做统一权限聚合服务
目标:
- 给定 `user_id`
- 返回:
- 角色列表
- 权限列表
- 每个权限点最终 data_scope
### C2. 做统一数据范围判定器
目标:
- 输入:用户 + 权限点 + 业务资源
- 输出:
- `ALL`
- `DEPT`
- `SELF`
### C3. 先接到核心接口
优先改:
- `/api/documents/list`
- `/api/audit/run/{RunId}`
- `/api/audit/result/{RunId}`
- `/api/users/list`
## 阶段 D:老用户数据迁移
### D1. 出迁移前检查 SQL
统计:
- 用户数
- 角色分布
- area 分布
- 无角色用户
- 空 area 用户
- 重复 sub / username
### D2. 出迁移脚本
做法:
- 先备份
- 再清洗 area
- 再导入 / 映射角色
- 再补默认角色
- 再跑校验
### D3. 迁移后验收
验收项:
- 登录正常
- `/api/auth/me` 正常
- 文档列表按地区隔离正常
- admin 不能跨区
- provincial_admin 能看全局
- common 只能看自己
## 阶段 E:安全与运维收口
### E1. 密码升级方案
- 兼容旧明文
- 新密码写哈希
- 后续批量升级
### E2. 审计日志
至少记录:
- 登录成功/失败
- 角色变更
- 用户地区变更
- 权限分配变更
### E3. 文档留档
要把以下文档保持最新:
- `docs/用户与地区权限完整设计方案.md`
- `docs/接口/用户权限与权限点清单.md`
- `docs/用户权限开发TaskList.md`
---
## 8. 推荐的实际开发顺序
如果按“马上开始干”的节奏,建议严格按下面顺序:
1. 先检查当前库真实 RBAC 表结构
2. 再把初始化 SQL 改成真实可执行版
3. 再改登录与 JWT
4. 再补 `/api/auth/me`
5. 再做权限聚合与数据范围注入
6. 再做老用户迁移脚本
7. 最后再做密码升级和审计收口
这个顺序的原因很简单:
- 不先确认表结构,后面代码全会写偏
- 不先收口登录态,前端无法稳定接入
- 不先做数据范围,地区隔离只是纸面方案
- 不最后做迁移,容易把脏数据带着跑
---
## 9. 我建议下一步立刻做什么
下一步最应该做的不是直接改 controller,而是:
### 第一步
先把**当前数据库里 7 张核心表的真实结构**完整导出来:
- `sso_users`
- `roles`
- `user_role`
- `permissions`
- `role_permissions`
- `sys_routes`
- `role_route`
### 第二步
基于真实结构,产出两份正式 SQL
- schema patch SQL
- seed SQL
### 第三步
再开始改:
- `authServiceImpl.py`
- `jwtService.py`
- `/api/auth/me`
也就是说,**下一阶段开发入口就是“数据库真相收口”**。