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

17 KiB
Raw Blame History

用户权限开发 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 里:

SELECT r.role_key ... LIMIT 1

这意味着:

  • 多角色用户会被截断成单角色
  • JWT 中的 roles 没真正使用起来
  • 后续 ALL > DEPT > SELF 的数据范围收敛逻辑无法成立

问题 3:JWT 里没有真正放入完整权限集

当前 JWT 虽然支持 roles 字段,但登录时只传了:

  • userRole
  • area

没有把:

  • 全量角色列表
  • 权限点列表
  • 最终数据范围摘要

稳定打进去。

这会导致:

  • /me 接口还不完整
  • 前端拿不到统一用户权限视图
  • 后端每次都要重新查库,且现有逻辑并未闭环

问题 4:当前没有统一的数据范围注入层

现在只是“能查角色 / 权限”,但还没有真正统一实现:

  • 文档列表自动按 area 过滤
  • 用户列表自动按 area 过滤
  • 评查 run / result 自动按文档归属校验

也就是说:

  • 功能权限雏形有了,数据权限还没有真正落地

问题 5:OAuth 登录仍然可能把 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

也就是说,下一阶段开发入口就是“数据库真相收口”