|
|
|
|
@ -0,0 +1,181 @@
|
|
|
|
|
# PEVC Local Account Initialization Implementation Plan
|
|
|
|
|
|
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
|
|
|
|
|
|
**Goal:** 按 PEVC 的模式内置学生 `tzs001`,本地只保存其 BCrypt 密码哈希;SSO 只投影身份和角色,不再读取主平台密码。
|
|
|
|
|
|
|
|
|
|
**Architecture:** Flyway 迁移一次性插入用户 ID `487`、学生快照和 `STUDENT` 角色关联,密码列仅存 BCrypt 哈希。平台 SSO/CAS 继续验证并投影身份;新投影用户使用随机 BCrypt 密码,和 PEVC 的 SSO 自动建号保持一致。移除当前分支中为镜像主平台密码新增的凭据查询与初始化器。
|
|
|
|
|
|
|
|
|
|
**Tech Stack:** Java 17, Spring Boot, Spring Security `PasswordEncoder`, Flyway, MyBatis-Plus, JUnit 5.
|
|
|
|
|
|
|
|
|
|
## Global Constraints
|
|
|
|
|
|
|
|
|
|
- 不修改 `E:\javawork\tianze-pro` 主平台工程。
|
|
|
|
|
- 不读取、记录、返回或提交主平台密码明文。
|
|
|
|
|
- 仅保留 `TEACHER`、`STUDENT` 两个角色,用户/角色无 CRUD 接口。
|
|
|
|
|
- `tzs001` 固定使用平台用户 ID `487` 和 `STUDENT` 角色。
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Task 1: 移除密码镜像防腐接口
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
- Delete: `src/main/java/com/yau/digitalrmb/platformintegration/application/PlatformCredentialRepository.java`
|
|
|
|
|
- Delete: `src/main/java/com/yau/digitalrmb/platformintegration/domain/PlatformCredential.java`
|
|
|
|
|
- Delete: `src/main/java/com/yau/digitalrmb/identity/application/PlatformCredentialInitializer.java`
|
|
|
|
|
- Modify: `src/main/java/com/yau/digitalrmb/platformintegration/infrastructure/JdbcPlatformIdentityRepository.java`
|
|
|
|
|
- Modify: `src/main/java/com/yau/digitalrmb/identity/application/PlatformIdentityProjectionService.java`
|
|
|
|
|
- Modify: `src/main/java/com/yau/digitalrmb/platformintegration/interfaces/PlatformSsoController.java`
|
|
|
|
|
- Modify: `src/main/java/com/yau/digitalrmb/platformintegration/interfaces/CasAuthenticationController.java`
|
|
|
|
|
- Test: `src/test/java/com/yau/digitalrmb/identity/PlatformIdentityProjectionServiceTest.java`
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
- Consumes: `PlatformIdentityProjectionService.project(PlatformActor)`.
|
|
|
|
|
- Produces: 所有 SSO/CAS 流程仅投影 `PlatformActor`,不包含密码对象或主平台密码查询。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 写出失败测试,证明新投影用户拥有 BCrypt 格式的随机密码**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
projectionService.project(actor);
|
|
|
|
|
UserEntity user = userMapper.selectById(actor.platformUserId());
|
|
|
|
|
assertThat(user.getPasswordHash()).startsWith("$2");
|
|
|
|
|
assertThat(passwordEncoder.matches("unknown", user.getPasswordHash())).isFalse();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
|
|
|
|
Run: `mvn -Dtest=PlatformIdentityProjectionServiceTest test -DforkCount=0 -B`
|
|
|
|
|
|
|
|
|
|
Expected: 旧实现写入 `{noop}EXTERNAL_SSO_ONLY`,断言失败。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 最小化实现**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
private void projectUser(PlatformActor actor) {
|
|
|
|
|
UserEntity user = userMapper.selectById(actor.platformUserId());
|
|
|
|
|
if (user == null) {
|
|
|
|
|
user = new UserEntity();
|
|
|
|
|
user.setId(actor.platformUserId());
|
|
|
|
|
user.setUsername(actor.account());
|
|
|
|
|
user.setPasswordHash(passwordEncoder.encode(UUID.randomUUID().toString()));
|
|
|
|
|
user.setEnabled(true);
|
|
|
|
|
userMapper.insert(user);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
user.setUsername(actor.account());
|
|
|
|
|
user.setEnabled(true);
|
|
|
|
|
userMapper.updateById(user);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
删除凭据类型、仓储、初始化器和所有 `findCredential` 调用;`JdbcPlatformIdentityRepository` 仅保留身份查询。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 运行针对性测试**
|
|
|
|
|
|
|
|
|
|
Run: `mvn -Dtest=PlatformIdentityProjectionServiceTest,PlatformSsoControllerTest test -DforkCount=0 -B`
|
|
|
|
|
|
|
|
|
|
Expected: PASS.
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: 提交**
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
git add src/main/java src/test/java
|
|
|
|
|
git commit -m "refactor: align sso with pevc local accounts"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Task 2: 以 Flyway 内置 tzs001 学生账号
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
- Create: `src/main/resources/db/migration/V3__seed_tzs001_local_student.sql`
|
|
|
|
|
- Test: `src/test/java/com/yau/digitalrmb/security/AuthControllerTest.java`
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
- Consumes: `sys_user(id, username, password_hash)`, `platform_user_snapshot`, `sys_user_role` 和现有角色 ID `1002`。
|
|
|
|
|
- Produces: 迁移后本地 `POST /api/v1/auth/login` 能用 `tzs001` 和指定初始密码签发 JWT;`GET /api/v1/auth/me` 返回 `STUDENT`。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 写出失败集成测试**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
mvc.perform(post("/api/v1/auth/login")
|
|
|
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
.content("{\"username\":\"tzs001\",\"password\":\"123qwe\"}"))
|
|
|
|
|
.andExpect(status().isOk())
|
|
|
|
|
.andExpect(jsonPath("$.data.accessToken").isNotEmpty());
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
移除测试 `@BeforeEach` 中的凭据投影,使测试只依赖迁移。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
|
|
|
|
Run: `mvn -Dtest=AuthControllerTest test -DforkCount=0 -B`
|
|
|
|
|
|
|
|
|
|
Expected: 登录返回 401,因为 V3 迁移尚不存在。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 添加仅含 BCrypt 哈希的迁移**
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
INSERT INTO sys_user (id, username, password_hash, enabled, created_at, updated_at, created_by, updated_by, deleted)
|
|
|
|
|
VALUES (487, 'tzs001', '$2a$10$ufcw5KFHtOmLzxAsV4C.MuIDOErMlw0iw5J5hc8OMzaTx0u9QYxG6', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'SYSTEM', 'SYSTEM', FALSE);
|
|
|
|
|
INSERT INTO platform_user_snapshot (platform_user_id, account, display_name, role_key, source_updated_at, synced_at)
|
|
|
|
|
VALUES (487, 'tzs001', 'tzs001', 'STUDENT', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
|
|
|
|
INSERT INTO sys_user_role (user_id, role_id) VALUES (487, 1002);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
最终 SQL 和日志均不得包含明文密码。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 运行集成测试**
|
|
|
|
|
|
|
|
|
|
Run: `mvn -Dtest=AuthControllerTest test -DforkCount=0 -B`
|
|
|
|
|
|
|
|
|
|
Expected: PASS,且 `/me` 角色为 `STUDENT`。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: 提交**
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
git add src/main/resources/db/migration/V3__seed_tzs001_local_student.sql src/test/java/com/yau/digitalrmb/security/AuthControllerTest.java
|
|
|
|
|
git commit -m "feat: seed tzs001 local student account"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Task 3: 清理配置、文档与回归验证
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
- Modify: `src/main/java/com/yau/digitalrmb/platformintegration/config/PlatformIntegrationProperties.java`
|
|
|
|
|
- Modify: `README.md`
|
|
|
|
|
- Modify: `docs/superpowers/specs/2026-08-03-platform-sso-readonly-design.md`
|
|
|
|
|
- Delete: `src/test/java/com/yau/digitalrmb/identity/PlatformCredentialInitializerTest.java`
|
|
|
|
|
- Modify: `src/test/java/com/yau/digitalrmb/platformintegration/infrastructure/JdbcPlatformIdentityRepositoryTest.java`
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
- Consumes: PEVC 对 SSO 与迁移账号的职责分离。
|
|
|
|
|
- Produces: 无 `local-login`、`PlatformCredential` 或主平台密码查询的可部署后端。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 写出仓储回归测试**
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
assertThat(repository.findByPlatformUserId(101L)).contains(actor);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
删除依赖 `core_user.PASSWORD` 的断言。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 移除过时配置与文档描述**
|
|
|
|
|
|
|
|
|
|
删除 `PlatformIntegrationProperties.LocalLogin`、密码镜像叙述及其测试;文档改为“SSO 身份投影 + Flyway 内置本地账号”。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 运行全量验证**
|
|
|
|
|
|
|
|
|
|
Run: `mvn test -DforkCount=0 -B`
|
|
|
|
|
|
|
|
|
|
Expected: 全部测试 PASS,0 failures,0 errors。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 构建可执行包**
|
|
|
|
|
|
|
|
|
|
Run: `mvn package -DskipTests -B`
|
|
|
|
|
|
|
|
|
|
Expected: `target/digital-rmb-backend-0.1.0-SNAPSHOT.jar` 生成成功。
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: 提交**
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
git add README.md docs/superpowers/specs src/main/java src/test/java
|
|
|
|
|
git commit -m "docs: document pevc-style local login"
|
|
|
|
|
```
|