新增权限:实现教师学员身份绑定与自服务安全控制
This commit is contained in:
1 parent
35832f2fce
commit
592a9655e8
38 files changed
+3277
-89
No files matched your search
@@ -50,14 +50,15 @@
|
||||
|
||||
## 2. 多身份策略与唯一性约束 (Multi-Identity Policy)
|
||||
|
||||
### 2.1 一期多身份决策:严格单身份互斥
|
||||
- 在铁路职工技能培训体系中,角色的职责边界极为森严:
|
||||
- **教务管理员 (Admin)**: 负责全局资源调配、排课、分班与监控。
|
||||
- **任课教师 (Teacher)**: 专职负责授课、课次考勤与教学答疑。
|
||||
- **参训职工 (Student)**: 专职参与培训、打卡签到与考核画像。
|
||||
- **冻结决策**: **一期系统严格不支持一个账号具备多重业务身份**。
|
||||
- 严禁同一个 `sys_user` 既绑定教师又绑定学员。
|
||||
- 严禁超级管理员账号 `admin (userId=1)` 绑定为普通业务教师或学员。
|
||||
### 2.1 一期多身份决策:业务主体身份互斥 (Teacher XOR Student)
|
||||
- 在铁路职工技能培训体系中,明确区分角色权限(Role)与业务档案身份(Identity):
|
||||
- **教务管理员 (Admin)**: 是系统权限角色(Role),负责全局资源调配、排课、分班与监控。
|
||||
- **任课教师 (Teacher)**: 是教学业务身份(Identity),负责授课、课次考勤与教学答疑。
|
||||
- **参训职工 (Student)**: 是参训业务身份(Identity),专职参与培训、打卡签到与考核画像。
|
||||
- **冻结决策**:
|
||||
- **Teacher 与 Student 业务身份严格互斥**:严禁同一个 `sys_user` 既绑定教师又绑定学员。
|
||||
- **Admin 是角色而非业务身份**:拥有 Admin 角色或管理权限的账号,若同时承担教学任务,允许绑定 Teacher 业务档案(Admin Role + Teacher Identity),并在自服务工作台中以当前教师身份推导数据范围。
|
||||
- **超级管理员账号环境纪律**:对默认超级管理员测试账号(如 `admin / userId=1`)的保护应通过运维环境数据纪律落实,业务服务层严禁硬编码 `userId=1` 永久禁止绑定。
|
||||
|
||||
### 2.2 数据库物理约束与保障机制
|
||||
为了在数据库持久层杜绝脏数据与多重绑定,在数据库 Migration 脚本中为两张表增加唯一索引:
|
||||
@@ -73,19 +74,19 @@ ON train_student(user_id)
|
||||
WHERE user_id IS NOT NULL AND del_flag = '0';
|
||||
```
|
||||
|
||||
### 2.3 业务服务层互斥前置校验防线
|
||||
在新建或绑定账号时,在 Java Service 事务中实施互斥断言:
|
||||
### 2.3 业务服务层互斥前置校验与跨表并发锁
|
||||
在新建或绑定账号时,在 Java Service 事务中实施悲观锁与互斥断言:
|
||||
```java
|
||||
public void validateUserIdentityExclusive(Long userId) {
|
||||
public void validateUserIdentityExclusive(Long userId, String targetType, String targetBusinessId) {
|
||||
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("该登录账号已绑定为学员身份,不可重复绑定");
|
||||
if ("TEACHER".equalsIgnoreCase(targetType)) {
|
||||
if (studentMapper.selectTrainStudentByUserId(userId) != null) {
|
||||
throw new ServiceException("该系统登录账号已绑定为学员身份,不可重复绑定为教师");
|
||||
}
|
||||
} else if ("STUDENT".equalsIgnoreCase(targetType)) {
|
||||
if (teacherMapper.selectTrainTeacherByUserId(userId) != null) {
|
||||
throw new ServiceException("该系统登录账号已绑定为教师身份,不可重复绑定为学员");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -46,16 +46,14 @@ RuoYi-Vue/sql/system/kingbase/
|
||||
ALTER TABLE train_teacher ADD COLUMN IF NOT EXISTS user_id BIGINT;
|
||||
ALTER TABLE train_student ADD COLUMN IF NOT EXISTS user_id BIGINT;
|
||||
|
||||
-- 2. 建立教师账号唯一索引 (忽略已删除 del_flag='2' 与空值)
|
||||
DROP INDEX IF EXISTS uq_train_teacher_user_id;
|
||||
CREATE UNIQUE INDEX uq_train_teacher_user_id
|
||||
ON train_teacher(user_id)
|
||||
-- 2. 建立教师账号唯一索引 (无 DROP,安全幂等,忽略已删除 del_flag='2' 与空值)
|
||||
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';
|
||||
|
||||
-- 3. 建立学员账号唯一索引
|
||||
DROP INDEX IF EXISTS uq_train_student_user_id;
|
||||
CREATE UNIQUE INDEX uq_train_student_user_id
|
||||
ON train_student(user_id)
|
||||
-- 3. 建立学员账号唯一索引 (无 DROP,安全幂等)
|
||||
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';
|
||||
|
||||
COMMENT ON COLUMN train_teacher.user_id IS '关联sys_user.user_id (唯一绑定教师登录账号)';
|
||||
@@ -66,26 +64,27 @@ RuoYi-Vue/sql/system/kingbase/
|
||||
|
||||
### 2.2 脚本 2: `005_training_roles_permissions.sql`
|
||||
- **执行目标**:
|
||||
1. 预置 3 个业务角色 (`train_admin`, `train_teacher`, `train_student`) 写入 `sys_role`。
|
||||
2. 补齐 `sys_menu` 中历史遗漏的基础模块按钮级权限(`train:teacher:*`, `train:student:*`, `train:course:*`, `train:plan:*`, `train:lesson:*` 等)。
|
||||
3. 将 `system:board:*` 权限标识收敛对齐为 `train:board:*`。
|
||||
4. 插入 Teacher 工作台菜单与 Student 个人中心菜单节点。
|
||||
5. 幂等配置 `sys_role_menu` 角色菜单权限映射。
|
||||
1. 内置 ID Collision Guard:预检 `role_id (3,4,5)` 与 `menu_id (2201..2240)`,若已被外部其他业务资源占用则显式 ABORT,严禁覆盖外来记录。
|
||||
2. 预置 3 个业务角色 (`train_admin`, `train_teacher`, `train_student`) 写入 `sys_role`。
|
||||
3. 补齐 `sys_menu` 中历史遗漏的基础模块按钮级权限(`train:teacher:*`, `train:student:*`, `train:course:*`, `train:plan:*`, `train:lesson:*` 等)。
|
||||
4. 将 `system:board:*` 权限标识收敛对齐为 `train:board:*`。
|
||||
5. 插入 Teacher 工作台菜单与 Student 个人中心菜单节点。
|
||||
6. 幂等配置 `sys_role_menu` 角色菜单权限映射。
|
||||
- **DML 设计核心内容**:
|
||||
```sql
|
||||
BEGIN;
|
||||
|
||||
-- 1. 预置角色 (使用特定固定 role_id 3, 4, 5,采用 ON CONFLICT DO NOTHING 保证幂等)
|
||||
-- 0. ID 碰撞守卫 (Collision Guard):检测 role_id 与 menu_id 是否有非预期占用,有则 RAISE EXCEPTION
|
||||
DO $$ ... $$;
|
||||
|
||||
-- 1. 预置角色 (使用 WHERE NOT EXISTS 确保无重复)
|
||||
INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_by, create_time, remark)
|
||||
VALUES
|
||||
(3, '培训管理员', 'train_admin', 3, '1', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '一期业务全局管理角色'),
|
||||
(4, '培训教师', 'train_teacher', 4, '2', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '教师专属教学工作台'),
|
||||
(5, '培训学员', 'train_student', 5, '2', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '学员专属个人培训中心')
|
||||
ON CONFLICT (role_id) DO NOTHING;
|
||||
SELECT 3, '培训管理员', 'train_admin', 3, '1', 1, 1, '0', '0', 'admin', CURRENT_TIMESTAMP, '', NULL, '一期业务全局管理角色'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_role WHERE role_id = 3 OR role_key = 'train_admin');
|
||||
|
||||
-- 2. 补齐基础管理模块按钮权限 (示例:教师管理按钮)
|
||||
-- 采用 WHERE NOT EXISTS 确保多次执行安全幂等
|
||||
-- ... (录入 train:teacher:list/add/edit/query/export 等节点)
|
||||
-- ... (录入 train:teacher:list/add/edit/query 等节点)
|
||||
|
||||
-- 3. 统一规范电子班牌命名空间
|
||||
UPDATE sys_menu SET perms = REPLACE(perms, 'system:board:', 'train:board:')
|
||||
@@ -93,8 +92,8 @@ RuoYi-Vue/sql/system/kingbase/
|
||||
|
||||
-- 4. 建立角色与菜单权限关联 (sys_role_menu)
|
||||
-- train_admin: 分配全部培训业务管理菜单及按钮
|
||||
-- train_teacher: 分配教师工作台、我的课表、我的班级学员菜单
|
||||
-- train_student: 分配学员中心、我的课表、我的报到、我的考勤菜单
|
||||
-- train_teacher: 分配教师工作台与专属自服务权限
|
||||
-- train_student: 分配学员培训中心与专属自服务权限
|
||||
|
||||
COMMIT;
|
||||
```
|
||||
|
||||
@@ -50,74 +50,83 @@ flowchart TD
|
||||
|
||||
## 2. 详细任务卡片清单 (RBAC-B1 ~ RBAC-B10)
|
||||
|
||||
### 任务 1: RBAC-B1 - 身份绑定与物理约束脚本 (Identity Binding & DDL)
|
||||
### 任务 1: RBAC-B1 - 身份绑定与物理约束脚本 (Identity Binding & DDL) [COMPLETED (Wave 1)]
|
||||
- **依赖关系**: 无前置依赖,首发任务。
|
||||
- **任务目标**:
|
||||
1. 编写 `RuoYi-Vue/sql/system/kingbase/004_rbac_identity_binding.sql`。
|
||||
2. 针对 `train_teacher(user_id)` 与 `train_student(user_id)` 建立非空部分唯一索引。
|
||||
- **完成标志**: 脚本在 Kingbase 生产库显式事务执行通过,唯一性拦截生效。
|
||||
- **当前状态**: 已完成 (脚本编写完成并通过静态契约测试验证,已就绪待运维发布)
|
||||
- **交付内容**:
|
||||
1. `RuoYi-Vue/sql/system/kingbase/004_rbac_identity_binding.sql`。
|
||||
2. 针对 `train_teacher(user_id)` 与 `train_student(user_id)` 建立非空部分唯一索引与约束验证块。
|
||||
3. `RbacPermissionMigrationContractTest` 验证通过。
|
||||
- **完成标志**: 脚本编写符合 Kingbase 语法,事务与约束验证完备。
|
||||
|
||||
### 任务 2: RBAC-B2 - 角色预置与权限补齐脚本 (Role & Permission Migration)
|
||||
### 任务 2: RBAC-B2 - 角色预置与权限补齐脚本 (Role & Permission Migration) [COMPLETED (Wave 1)]
|
||||
- **依赖关系**: 依赖 B1 完成。
|
||||
- **任务目标**:
|
||||
1. 编写 `RuoYi-Vue/sql/system/kingbase/005_training_roles_permissions.sql`。
|
||||
- **当前状态**: 已完成 (脚本编写完成并通过静态契约测试验证,已就绪待运维发布)
|
||||
- **交付内容**:
|
||||
1. `RuoYi-Vue/sql/system/kingbase/005_training_roles_permissions.sql`。
|
||||
2. 预置 `train_admin` (3), `train_teacher` (4), `train_student` (5) 角色。
|
||||
3. 补齐 `sys_menu` 中基础管理模块缺失的全部按钮级 `perms` 行。
|
||||
4. 建立角色的初始菜单与功能权限绑定映射。
|
||||
- **完成标志**: 数据库执行无报错,管理员界面角色管理中可见 3 个新角色。
|
||||
3. 补齐 `sys_menu` 中基础管理模块缺失的全部按钮级 `perms` 行 (2201~2240)。
|
||||
4. 建立角色的初始菜单与功能权限绑定映射及自检验证块。
|
||||
- **完成标志**: 脚本契约测试 `testMigration005_RoleAndPermissionScriptContract` 验证通过。
|
||||
|
||||
### 任务 3: RBAC-B3 - 教师后端自服务体系实现 (Teacher Backend)
|
||||
### 任务 3: RBAC-B3 - 教师后端自服务体系实现 (Teacher Backend) [COMPLETED (Wave 1)]
|
||||
- **依赖关系**: 依赖 B1, B2。与 B4、B7、B8 可完全并行。
|
||||
- **任务目标**:
|
||||
1. 新增控制器 `TrainTeacherMeController.java` (`/train/me/...`)。
|
||||
2. 实现获取教师本人画像、任教班级、授课课表、班级学员名册(脱敏)与出勤统计。
|
||||
3. 强制从 `SecurityUtils.getUserId()` 提取当前教师 ID。
|
||||
- **完成标志**: Swagger 联调成功,篡改身份直接抛出 403。
|
||||
- **当前状态**: 已完成
|
||||
- **交付内容**:
|
||||
1. 控制器 `TrainTeacherMeController.java` (`/train/me/teacher/...`)。
|
||||
2. 实现获取教师本人画像、任教班级、授课课表、班级学员名册(脱敏)与课次出勤流水。
|
||||
3. 强制校验教师身份与教学班级/课次归属,杜绝跨教师越权 (IDOR)。
|
||||
4. `TeacherSelfServiceApiTest` 7 个单测用例全部通过。
|
||||
- **完成标志**: 接口单元测试通过率 100%,越权拦截测试生效。
|
||||
|
||||
### 任务 4: RBAC-B4 - 学员后端自服务体系实现 (Student Backend)
|
||||
### 任务 4: RBAC-B4 - 学员后端自服务体系实现 (Student Backend) [COMPLETED (Wave 1)]
|
||||
- **依赖关系**: 依赖 B1, B2。与 B3、B7、B8 可完全并行。
|
||||
- **任务目标**:
|
||||
1. 新增控制器 `TrainStudentMeController.java` (`/train/me/...`)。
|
||||
- **当前状态**: 已完成
|
||||
- **交付内容**:
|
||||
1. 控制器 `TrainStudentMeController.java` (`/train/me/student/...`)。
|
||||
2. 实现获取学员本人档案、参训班级状态、个人课表、报到凭据、个人考勤、累计学时与多维画像。
|
||||
3. 强制校验本人归属,杜绝任何外部主键传入。
|
||||
- **完成标志**: 接口单元测试通过率 100%。
|
||||
4. `StudentSelfServiceApiTest` 6 个单测用例全部通过。
|
||||
- **完成标志**: 接口单元测试通过率 100%,敏感信息脱敏合格。
|
||||
|
||||
### 任务 5: RBAC-B5 - 教师工作台前端视图开发 (Teacher Frontend)
|
||||
### 任务 5: RBAC-B5 - 教师工作台前端视图开发 (Teacher Frontend) [PENDING (Wave 2)]
|
||||
- **依赖关系**: 依赖 B2 菜单路由,可与 B3 并行(采用 Mock 或接口契约联调)。
|
||||
- **任务目标**:
|
||||
1. 在 `build_ui/src/views/train/teacher/` 下开发工作台看板与我的日程日历组件。
|
||||
2. 开发任教班级花名册抽屉视图。
|
||||
- **完成标志**: 教师登录后正常展现日历课表与花名册。
|
||||
|
||||
### 任务 6: RBAC-B6 - 学员个人培训中心前端开发 (Student Frontend)
|
||||
### 任务 6: RBAC-B6 - 学员个人培训中心前端开发 (Student Frontend) [PENDING (Wave 2)]
|
||||
- **依赖关系**: 依赖 B2 菜单路由,可与 B4 并行开发。
|
||||
- **任务目标**:
|
||||
1. 在 `build_ui/src/views/train/student/` 下开发学员培训个人中心。
|
||||
2. 整合培训流程步骤条、今日课表卡片、个人考勤打卡流水与雷达画像组件。
|
||||
- **完成标志**: 学员登录后清晰直观呈现个人培训全流程状态。
|
||||
|
||||
### 任务 7: RBAC-B7 - 登录界面注册入口安全改造 (Login UI Policy)
|
||||
### 任务 7: RBAC-B7 - 登录界面注册入口安全改造 (Login UI Policy) [PENDING (Wave 2)]
|
||||
- **依赖关系**: 独立任务,可立即开工。
|
||||
- **任务目标**:
|
||||
1. 修改 `build_ui/src/views/login.vue`,彻底关闭 `register` 开关,移除“立即注册”链接。
|
||||
2. 增加居中提示:“*账号由培训管理部门统一创建与授权维护*”。
|
||||
- **完成标志**: 登录页面无注册链接,提示文案清晰优雅。
|
||||
|
||||
### 任务 8: RBAC-B8 - 班牌权限命名空间统一对齐 (Namespace Alignment)
|
||||
### 任务 8: RBAC-B8 - 班牌权限命名空间统一对齐 (Namespace Alignment) [PARTIALLY COMPLETED (Wave 1 后端已完成)]
|
||||
- **依赖关系**: 独立任务,可立即开工。
|
||||
- **任务目标**:
|
||||
1. 将后端 `TrainElectronicBoardController.java` 中的 `@PreAuthorize("@ss.hasPermi('system:board:...')")` 统一对齐为 `train:board:...`。
|
||||
2. 将前端 `views/train/board/index.vue` 中的 `v-hasPermi="['system:board:...']"` 统一对齐为 `train:board:...`。
|
||||
- **完成标志**: 班牌功能按钮与后端权限完全基于 `train:board:*` 正常鉴权。
|
||||
- **当前状态**:
|
||||
- 后端:`TrainElectronicBoardController.java` 中的权限注解已全部从 `system:board:*` 收敛统一为 `train:board:*` [COMPLETED]
|
||||
- 前端:`build_ui/src/views/train/board/index.vue` 中的 `v-hasPermi` 对齐计划在 Wave 2 前端阶段完成 [PENDING]
|
||||
- **完成标志**: 静态契约测试 `testElectronicBoardControllerPermissionsAligned` 验证通过。
|
||||
|
||||
### 任务 9: RBAC-B9 - 数据范围与 IDOR 安全渗透自动化测试 (IDOR Gate)
|
||||
### 任务 9: RBAC-B9 - 数据范围与 IDOR 安全渗透自动化测试 (IDOR Gate) [PARTIALLY COMPLETED (Wave 1 后端 IDOR 已通过)]
|
||||
- **依赖关系**: 依赖 B3、B4、B5、B6 联调完成。
|
||||
- **任务目标**:
|
||||
1. 编写跨用户越权自动化探测脚本,模拟 Teacher A 访问 Teacher B 课表,模拟 Student A 访问 Student B 档案与考勤。
|
||||
2. 验证所有直接对象引用均被有效拒止。
|
||||
- **完成标志**: `IDOR_LEAK_COUNT = 0`。
|
||||
- **当前状态**:
|
||||
- 后端 IDOR 单测套件已完成并验证:
|
||||
- `RbacIdorSecurityTest`: 模拟跨教师越权访问他人学员名册与考勤,跨学员越权探测等,全部被严密拒止。
|
||||
- `TrainingIdentityServiceTest`: 验证身份唯一性与互斥性。
|
||||
- 端到端渗透验收:保留至三角色前端集成后进行。
|
||||
- **完成标志**: 后端自动化测试中 `IDOR_LEAK_COUNT = 0`。
|
||||
|
||||
### 任务 10: RBAC-B10 - 管理端业务全流程无损回归测试 (Admin Regression)
|
||||
### 任务 10: RBAC-B10 - 管理端业务全流程无损回归测试 (Admin Regression) [PENDING (Wave 3)]
|
||||
- **依赖关系**: 汇总任务,依赖全部前置任务。
|
||||
- **任务目标**:
|
||||
1. 执行 E2E-R2 验收方案全流程。
|
||||
@@ -126,11 +135,17 @@ flowchart TD
|
||||
|
||||
---
|
||||
|
||||
## 3. 并行施工调度建议
|
||||
## 3. 并行施工调度建议与 Wave 进展
|
||||
|
||||
- **第 1 梯队 (基础组)**: 执行 `RBAC-B1` 与 `RBAC-B2` (预计 0.5 天),完成数据库准备;同时执行 `RBAC-B7` 与 `RBAC-B8` (预计 0.5 天)。
|
||||
- **第 2 梯队 (业务组)**:
|
||||
- 后端工程师 A 攻坚 `RBAC-B3` (教师后端),前端工程师 A 攻坚 `RBAC-B5` (教师前端);
|
||||
- 后端工程师 B 攻坚 `RBAC-B4` (学员后端),前端工程师 B 攻坚 `RBAC-B6` (学员前端);
|
||||
- 两组完全解耦并行。
|
||||
- **第 3 梯队 (质量保障组)**: 执行 `RBAC-B9` (越权审计) 与 `RBAC-B10` (全量回归与演示交付)。
|
||||
- **Wave 1 (已完成)**:
|
||||
- 后端基础设施与迁移脚本准备: `RBAC-B1`, `RBAC-B2` (完成)
|
||||
- 核心身份服务与自服务后端: `RBAC-B3`, `RBAC-B4` (完成)
|
||||
- 班牌后端权限收敛: `RBAC-B8 (后端)` (完成)
|
||||
- 安全与契约单元测试: `RBAC-B9 (后端)` (完成,194/194 PASS)
|
||||
- **Wave 2 (待推进)**:
|
||||
- 教师工作台前端视图开发: `RBAC-B5`
|
||||
- 学员个人培训中心前端开发: `RBAC-B6`
|
||||
- 登录入口安全策略改造: `RBAC-B7`
|
||||
- 班牌前端权限指令对齐: `RBAC-B8 (前端)`
|
||||
- **Wave 3 (最终验收)**:
|
||||
- 三角色端到端联调与 E2E-R2 回归测试: `RBAC-B10`
|
||||
Reference in new issue
Block a user