8.1 KiB
8.1 KiB
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。
- 架构优势:
- 零新增物理表: 在前置 V2 数据库迁移脚本
003_alter_master_tables.sql中,已在train_teacher和train_student表物理添加了user_id列,现有实体类和 Mapper XML 均已就绪。 - 极速单表/外联查询: 获取当前登录人的教师 ID 或学员 ID 时,直接执行
SELECT t_id FROM train_teacher WHERE user_id = #{userId},单索引点查,响应时延 < 1ms。 - 改造面最小: 领域模型与既有 MyBatis 实体完全兼容,无需重构现有领域对象树。
- 零新增物理表: 在前置 V2 数据库迁移脚本
- 劣势与局限:
- 若未来同一个自然人同时具备“讲师”和“学员”双重身份,直联模式需要跨两张表查询或处理两份主体数据。
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。
- 新建映射表
- 架构优势:
- 结构高度解耦,天然支持未来“一人多身份”、“多端身份动态切换”等超大规模平台需求。
- 劣势与局限:
- 需要新建物理表、维护新的外键与索引,增加数据库 Migration 的复杂度和风险。
- 每次根据登录人推导数据范围均需多一层 JOIN 或一次额外的主键转换查询。
- 大幅增加现有 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 账号创建推荐模式:表单内可选“同时开通系统账号”
- 业务流程:
- 管理员在录入教师或学员档案时,表单底部勾选【开通系统登录账号】开关(默认勾选)。
- 系统自动推荐登录账号格式:
- 教师账号: 优先采用工号(如
T2026001),若未填工号则采用手机号。 - 学员账号: 优先采用学员编号/工号(如
GH001),若无则采用手机号。
- 教师账号: 优先采用工号(如
- 初始密码策略:
- 统一设置初始受控密码:
Railway@2026。 - 采用 BCrypt 强哈希加密存储入库。
- 强制将
sys_user.pwd_update_date设为NULL,触发前端首次登录时强制要求用户修改密码的安全拦截。
- 统一设置初始受控密码:
- 角色自动赋予:
- 创建教师账号时,自动关联向
sys_user_role插入role_id = <train_teacher>。 - 创建学员账号时,自动关联向
sys_user_role插入role_id = <train_student>。
- 创建教师账号时,自动关联向
- 整个创建过程置于单个本地数据库事务中(
@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 会话缓存,实现“秒级下线”。
- 业务 Service 在同一事务中联动更新关联的
- 当业务教师重新启用 (
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在任何时候均可完整追溯责任人。
- 业务表更新