Files
railwaysystem/docs/development/rbac-r2/01_identity_binding_design.md
T

8.1 KiB
Raw Blame History

RailwaySystem 身份绑定与账号生命周期设计 (Identity Binding Design)

  • 设计版本: R.2A Design Freeze
  • 设计日期: 2026-09-15
  • 核心目标: 建立 sys_user 系统登录账户与 train_teacher (教师)、train_student (学员) 业务主体之间的确定性逻辑绑定模型,规范生命周期流转与唯一性约束。

1. 业务主体关联方案比较与最终选型

为了将系统登录账户(sys_user)与铁路培训业务实体绑定,针对系统架构演进,深入比较以下两个设计方案:

1.1 方案 A:在业务主体表中直联 user_id (推荐方案)

  • 模型设计:
    • train_teacher 表中直接维护 user_id BIGINT 列,逻辑关联 sys_user.user_id。
    • train_student 表中直接维护 user_id BIGINT 列,逻辑关联 sys_user.user_id。
  • 架构优势:
    1. 零新增物理表: 在前置 V2 数据库迁移脚本 003_alter_master_tables.sql 中,已在 train_teacher 和 train_student 表物理添加了 user_id 列,现有实体类和 Mapper XML 均已就绪。
    2. 极速单表/外联查询: 获取当前登录人的教师 ID 或学员 ID 时,直接执行 SELECT t_id FROM train_teacher WHERE user_id = #{userId},单索引点查,响应时延 < 1ms。
    3. 改造面最小: 领域模型与既有 MyBatis 实体完全兼容,无需重构现有领域对象树。
  • 劣势与局限:
    • 若未来同一个自然人同时具备“讲师”和“学员”双重身份,直联模式需要跨两张表查询或处理两份主体数据。

1.2 方案 B:引入统一业务身份映射表 train_user_identity

  • 模型设计:
    • 新建映射表 train_user_identity (id, user_id, identity_type, business_id, status, create_time)。
    • identity_type: TEACHER 对应 t_id, STUDENT 对应 s_id。
  • 架构优势:
    1. 结构高度解耦,天然支持未来“一人多身份”、“多端身份动态切换”等超大规模平台需求。
  • 劣势与局限:
    1. 需要新建物理表、维护新的外键与索引,增加数据库 Migration 的复杂度和风险。
    2. 每次根据登录人推导数据范围均需多一层 JOIN 或一次额外的主键转换查询。
    3. 大幅增加现有 Service 和 Mapper 的代码改造量,过度设计(Over-Engineering)。

1.3 综合决策对比矩阵与最终推荐

评估维度 方案 A:直联 user_id (现有预留) 方案 B:统一映射表 train_user_identity 权重 / 判定
与现有 DDL 契合度 100% (列已存在,实体已映射) 0% (需新建表与迁移脚本) 方案 A 显著优胜
查询性能与简单度 极佳 (单表直查,无多余 JOIN) 一般 (多一层关系表关联) 方案 A 胜
现有代码修改量 极小 (仅需在 Service 层赋值) 较大 (需新增 Mapper/Service) 方案 A 胜
数据一致性与约束 单列唯一索引即刻保证 需要多列复合唯一约束 方案 A 胜
一期交付稳定性 极高 (稳定无副作用) 中 (存在映射脏数据风险) 方案 A 胜
未来多身份扩展性 弱 (仅支持单一身份绑定) 强 (天生支持多重身份) 方案 B 胜

最终冻结决策: 采用方案 A(RECOMMENDED_IDENTITY_MODEL = DIRECT_USER_ID)。 以最小的改动、最高的稳定性,完美利用已有的 Kingbase DDL 物理列,达成一期业务 100% 闭环。


2. 多身份策略与唯一性约束 (Multi-Identity Policy)

2.1 一期多身份决策:严格单身份互斥

  • 在铁路职工技能培训体系中,角色的职责边界极为森严:
    • 教务管理员 (Admin): 负责全局资源调配、排课、分班与监控。
    • 任课教师 (Teacher): 专职负责授课、课次考勤与教学答疑。
    • 参训职工 (Student): 专职参与培训、打卡签到与考核画像。
  • 冻结决策: 一期系统严格不支持一个账号具备多重业务身份。
    • 严禁同一个 sys_user 既绑定教师又绑定学员。
    • 严禁超级管理员账号 admin (userId=1) 绑定为普通业务教师或学员。

2.2 数据库物理约束与保障机制

为了在数据库持久层杜绝脏数据与多重绑定,在数据库 Migration 脚本中为两张表增加唯一索引:

-- 1. 教师账号唯一索引 (忽略 NULL,只对已绑定的 user_id 施加唯一约束)
CREATE UNIQUE INDEX IF NOT EXISTS uq_train_teacher_user_id 
ON train_teacher(user_id) 
WHERE user_id IS NOT NULL AND del_flag = '0';

-- 2. 学员账号唯一索引 (忽略 NULL,只对已绑定的 user_id 施加唯一约束)
CREATE UNIQUE INDEX IF NOT EXISTS uq_train_student_user_id 
ON train_student(user_id) 
WHERE user_id IS NOT NULL AND del_flag = '0';

2.3 业务服务层互斥前置校验防线

在新建或绑定账号时,在 Java Service 事务中实施互斥断言:

public void validateUserIdentityExclusive(Long userId) {
    if (userId == null) return;
    if (SecurityUtils.isAdmin(userId)) {
        throw new ServiceException("系统超级管理员不可绑定为业务教师或学员");
    }
    if (teacherMapper.countByUserId(userId) > 0) {
        throw new ServiceException("该登录账号已绑定为教师身份,不可重复绑定");
    }
    if (studentMapper.countByUserId(userId) > 0) {
        throw new ServiceException("该登录账号已绑定为学员身份,不可重复绑定");
    }
}

3. 用户创建与账号生命周期联动机制

3.1 账号创建推荐模式:表单内可选“同时开通系统账号”

  • 业务流程:
    1. 管理员在录入教师或学员档案时,表单底部勾选【开通系统登录账号】开关(默认勾选)。
    2. 系统自动推荐登录账号格式:
      • 教师账号: 优先采用工号(如 T2026001),若未填工号则采用手机号。
      • 学员账号: 优先采用学员编号/工号(如 GH001),若无则采用手机号。
    3. 初始密码策略:
      • 统一设置初始受控密码:Railway@2026。
      • 采用 BCrypt 强哈希加密存储入库。
      • 强制将 sys_user.pwd_update_date 设为 NULL,触发前端首次登录时强制要求用户修改密码的安全拦截。
    4. 角色自动赋予:
      • 创建教师账号时,自动关联向 sys_user_role 插入 role_id = <train_teacher>。
      • 创建学员账号时,自动关联向 sys_user_role 插入 role_id = <train_student>。
    5. 整个创建过程置于单个本地数据库事务中(@Transactional(rollbackFor = Exception.class)),若任意一步失败,整体回滚,杜绝孤立僵尸账号。

3.2 补录与独立绑定能力 (兜底机制)

  • 对于历史导入或初次创建时未开通账号的主体,在教师/学员管理列表的操作列增加【开通账号】或【重置密码】按钮,支持补录生成 sys_user 并回填 user_id。

4. 删除、停用与离职审计策略

在国家关键信息基础设施与铁路行业规范中,系统必须满足操作可追溯与数据终身审计要求:

4.1 离职与停用策略 (Status Synchronization)

  • 当业务教师被设置为停用 (train_teacher.status = 0),或学员由于违反纪律被停用 (train_student.status = 0):
    • 业务 Service 在同一事务中联动更新关联的 sys_user.status = '1' (停用)。
    • 清理该用户在 Redis 中的在线 Token 会话缓存,实现“秒级下线”。
  • 当业务教师重新启用 (status = 1),联动更新 sys_user.status = '0' (正常)。

4.2 软删除与历史归档策略 (Zero Physical Deletion)

  • 红线要求: 系统严禁对任何已产生过教学、考勤、报到记录的账号执行物理 DELETE!
  • 当管理员在界面上删除教师或学员时:
    • 业务表更新 del_flag = '2'。
    • 关联系统用户表更新 sys_user.del_flag = '2'。
    • 保留 train_teacher.user_id 与 train_student.user_id 的数值指针不变,确保历史系统操作日志 (sys_oper_log)、课次考勤打卡流水 (train_student_checkin) 中的 create_by 和 user_id 在任何时候均可完整追溯责任人。