17 KiB
用户权限开发 TaskList
目标:在
leaudit-platform里,基于当前真实业务落地一套 单地区隔离 + 角色权限 + 数据范围控制 的用户体系,并能把老系统用户数据平滑迁移过来。
这份文档不是泛泛设计稿,而是后续开发的执行清单。
1. 当前结论先说清楚
当前这条线,应该按下面原则做,不要再发散:
- 用户地区只认
sso_users.area - 数据隔离只做单地区,不做多地区授权
- 当前业务角色只保留:
provincial_adminadmincommon
super_admin只作为可选系统维护角色- 数据范围只保留:
ALLDEPTSELF
- 新系统要兼容老系统已有数据结构,不要为了“理论优雅”把老数据迁移难度抬高
2. 当前新系统现状盘点
2.0 本次实际检查结果(2026-04-29)
我已经实际检查了当前 leaudit_platform 新库和老库 docauditai,结论如下:
- 新库
leaudit_platform原先 完全没有 这 7 张核心 RBAC 表:sso_usersrolesuser_rolepermissionsrole_permissionssys_routesrole_route
- 新库现阶段只有
leaudit_*业务表,所以原有认证/权限代码其实处于“代码已写、库表未落地”的状态 - 我已经补了可执行 SQL:
scripts/user_rbac_schema_patch.sqlscripts/user_rbac_seed.sqlscripts/user_rbac_migration_audit.sql
- 我已经把
schema_patch + seed执行进当前新库 - 当前新库 RBAC 初始化结果:
roles = 4permissions = 30role_permissions = 90sys_routes = 9role_route = 30sso_users = 0user_role = 0
老库 docauditai 的迁移审计关键结果:
sso_users = 4106roles = 3user_role = 11permissions = 133role_permissions = 222sys_routes = 34role_route = 95- 老库 没有空地区、没有重复 sub、没有重复 username
- 老库 4106 个用户里有 4098 个没有角色
- 老库真实角色分布非常集中:
common = 6admin = 4provincial_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.pyfastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.pyfastapi_common/fastapi_common_security/jwtService.pyfastapi_common/fastapi_common_security/security.pyfastapi_modules/fastapi_leaudit/controllers/auth/authController.py
2.3 当前最关键的问题
问题 1:权限设计文档和实际代码字段名不一致
当前代码查的是:
roles.role_keypermissions.permission_keyrole_permissions.grant_type
但我前面新写的初始化 SQL 用的是:
roles.role_namepermissions.permission_code
这说明:
- 现阶段不能直接执行那份初始化 SQL 到现有库
- 必须先按当前实际数据库字段重新收一版正式建表/初始化方案
问题 2:登录后只取“一个角色”
当前 authServiceImpl.py 里:
SELECT r.role_key ... LIMIT 1
这意味着:
- 多角色用户会被截断成单角色
- JWT 中的
roles没真正使用起来 - 后续
ALL > DEPT > SELF的数据范围收敛逻辑无法成立
问题 3:JWT 里没有真正放入完整权限集
当前 JWT 虽然支持 roles 字段,但登录时只传了:
userRolearea
没有把:
- 全量角色列表
- 权限点列表
- 最终数据范围摘要
稳定打进去。
这会导致:
/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_usersrolesuser_rolepermissionsrole_permissionssys_routesrole_route
3.1 老系统 sso_users 关键字段
老系统 sso_users 目前至少包含:
idsubusernamenick_namephone_numberemailou_idou_namestatusis_leaderpasswordtry_counttry_login_timeareatenant_namedep_short_namedep_namemq_person_uuidmq_account_uuidmq_synced_atcreated_atupdated_atdeleted_at
迁移判断
这说明:
- 新系统完全没必要重新发明用户主表
- 最优方案是:
- 继续沿用
sso_users - 补必要索引/约束/注释
- 修正其业务语义
- 继续沿用
3.2 老系统 roles 关键字段
老系统 roles 目前至少包含:
idrole_keyrole_namedata_scopedescriptionparent_role_idpriorityis_system_rolepermissions_cachemetadatacreated_atupdated_at
迁移判断
建议:
- 保留
role_key作为机器标识 - 保留
role_name作为中文/展示名 - 继续使用
data_scope parent_role_id / permissions_cache / metadata可以先保留但不作为第一阶段核心依赖
3.3 老系统 permissions 关键字段
老系统 permissions 目前至少包含:
idpermission_keymoduleresourceactiondescriptiondisplay_namepermission_typeis_systemmetadataparent_idsort_orderroute_idapi_pathapi_methodcreated_atupdated_at
迁移判断
建议:
- 不要再新造
permission_code - 直接沿用
permission_key - 后续新系统全部按
permission_key统一
3.4 老系统 role_permissions 关键字段
老系统 role_permissions 目前至少包含:
role_idpermission_idgrant_typedata_scopecondition_filtermetadatacreated_atupdated_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_adminrole_name:中文展示名,例如“省级管理员”data_scope:默认数据范围
建议正式保留的角色:
provincial_adminadmincommonsuper_admin(可选)
4.3 permissions 目标策略
继续沿用:
permission_keyapi_pathapi_methodroute_id
建议后续所有新权限都按下面格式命名:
auth:me:readdocuments:list:readdocuments:upload:writeaudit:run:executerules:binding:update
不要混用:
- 一部分
documents.list - 一部分
document:read:all
必须统一成一种风格。
我建议
直接收口成老系统已有风格:
module:resource:action
这样能和老数据完全对齐。
4.4 role_permissions 目标策略
继续沿用:
grant_typedata_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_namepermission_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 落地
要把当前用户的:
- 基本信息
arearolespermissions
统一返回。
P1:第二阶段紧跟着修
5.6 数据范围注入
至少要先覆盖:
- 文档列表
- 文档详情
- 用户列表
- 评查状态 / 结果
5.7 密码校验升级
短期兼容旧明文,长期迁移到哈希:
- 登录时支持“旧明文兼容 + 新哈希优先”
- 用户下次修改密码时写入哈希
5.8 权限缓存 / 权限聚合
后续可以考虑:
- JWT 轻载
- 服务端缓存权限聚合结果
但这不是 P0。
6. 老系统用户数据迁移策略
6.1 迁移原则
不是“把老用户复制一份到新表”,而是:
- 尽可能复用原表结构
- 用增量清洗 + 角色校正 + 地区校正的方式迁移
6.2 迁移对象
第一阶段只迁这几类数据:
sso_usersrolesuser_rolepermissionsrole_permissionssys_routesrole_route
6.3 sso_users 迁移规则
必迁字段
idsubusernamenick_namephone_numberemailou_idou_namestatusis_leaderpasswordareatenant_namedep_namedep_short_namecreated_atupdated_atdeleted_at
可选迁字段
mq_person_uuidmq_account_uuidmq_synced_attry_counttry_login_time
迁移前校验
要先出统计:
sub是否有重复username是否有重复area是否为空status != 0的禁用用户数量deleted_at is not null的软删除用户数量
6.4 角色映射规则
要先梳理老库中真实 role_key 分布。
预期映射:
provincial_admin→ 保留admin→ 保留common→ 保留- 其他历史角色:
- 先做映射表
- 无法归类的先落到
common - 再人工复核
明确不再延续的角色
city_adminreview_managerreview_userrule_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. 做统一数据范围判定器
目标:
- 输入:用户 + 权限点 + 业务资源
- 输出:
ALLDEPTSELF
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/用户与地区权限完整设计方案.mddocs/接口/用户权限与权限点清单.mddocs/用户权限开发TaskList.md
8. 推荐的实际开发顺序
如果按“马上开始干”的节奏,建议严格按下面顺序:
- 先检查当前库真实 RBAC 表结构
- 再把初始化 SQL 改成真实可执行版
- 再改登录与 JWT
- 再补
/api/auth/me - 再做权限聚合与数据范围注入
- 再做老用户迁移脚本
- 最后再做密码升级和审计收口
这个顺序的原因很简单:
- 不先确认表结构,后面代码全会写偏
- 不先收口登录态,前端无法稳定接入
- 不先做数据范围,地区隔离只是纸面方案
- 不最后做迁移,容易把脏数据带着跑
9. 我建议下一步立刻做什么
下一步最应该做的不是直接改 controller,而是:
第一步
先把当前数据库里 7 张核心表的真实结构完整导出来:
sso_usersrolesuser_rolepermissionsrole_permissionssys_routesrole_route
第二步
基于真实结构,产出两份正式 SQL:
- schema patch SQL
- seed SQL
第三步
再开始改:
authServiceImpl.pyjwtService.py/api/auth/me
也就是说,下一阶段开发入口就是“数据库真相收口”。