10 KiB
Backend Password Transfer Encryption Implementation Plan
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 为正式密码提交接口补上后端解密链路,让 /login、/register、/system/user/profile/updatePwd、/system/user/resetPwd、/system/user 在收到密文密码后先解密,再复用现有认证与 BCrypt 逻辑。
Architecture: 在 ruoyi-framework 新增统一的密码传输解密服务,固定密钥从配置读取,负责 AES/Base64 解密和失败抛错。ruoyi-admin 各控制器在进入现有业务逻辑前显式调用该服务对密码字段解密,/login/test 保持不变。
Tech Stack: Spring Boot 3.5、JUnit 5、MockMvc、JDK javax.crypto、Maven Surefire
Task 1: 搭建后端密码解密基础设施
Files:
-
Create:
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PasswordTransferCryptoService.java -
Create:
ruoyi-framework/src/test/java/com/ruoyi/framework/web/service/PasswordTransferCryptoServiceTest.java -
Modify:
ruoyi-admin/src/main/resources/application.yml -
Modify:
ruoyi-admin/src/main/resources/application-dev.yml -
Step 1: 写解密服务失败用例
class PasswordTransferCryptoServiceTest
{
@Test
void shouldDecryptValidCipherText()
{
String plain = service.decrypt("Base64密文");
assertEquals("admin123", plain);
}
@Test
void shouldRejectInvalidCipherText()
{
assertThrows(ServiceException.class, () -> service.decrypt("not-base64"));
}
}
- Step 2: 运行测试确认当前失败
Run: mvn -pl ruoyi-framework -am -Dtest=PasswordTransferCryptoServiceTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: FAIL,提示测试类或 PasswordTransferCryptoService 不存在
- Step 3: 补配置与最小实现
@Service
public class PasswordTransferCryptoService
{
@Value("${security.password-transfer.key}")
private String key;
public String decrypt(String cipherText)
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"));
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)), StandardCharsets.UTF_8);
}
}
security:
password-transfer:
key: "请替换为16位固定密钥"
- Step 4: 重新运行基础测试
Run: mvn -pl ruoyi-framework -am -Dtest=PasswordTransferCryptoServiceTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: PASS
- Step 5: 提交本任务
git add ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PasswordTransferCryptoService.java ruoyi-framework/src/test/java/com/ruoyi/framework/web/service/PasswordTransferCryptoServiceTest.java ruoyi-admin/src/main/resources/application.yml ruoyi-admin/src/main/resources/application-dev.yml
git commit -m "新增密码传输解密服务"
Task 2: 接入登录与注册接口解密
Files:
-
Modify:
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java -
Modify:
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java -
Create:
ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysLoginControllerPasswordTransferTest.java -
Create:
ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysRegisterControllerPasswordTransferTest.java -
Step 1: 写登录与注册控制器失败测试
mockMvc.perform(post("/login")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"username\":\"admin\",\"password\":\"cipher\",\"code\":\"1\",\"uuid\":\"u\"}"))
.andExpect(status().isOk());
verify(passwordTransferCryptoService).decrypt("cipher");
verify(loginService).login("admin", "admin123", "1", "u");
mockMvc.perform(post("/register")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"username\":\"u1\",\"password\":\"cipher\",\"code\":\"1\",\"uuid\":\"u\"}"))
.andExpect(status().isOk());
verify(passwordTransferCryptoService).decrypt("cipher");
verify(registerService).register(any(RegisterBody.class));
- Step 2: 运行登录/注册测试确认失败
Run: mvn -pl ruoyi-admin -am -Dtest=SysLoginControllerPasswordTransferTest,SysRegisterControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: FAIL,控制器尚未调用解密服务
- Step 3: 在正式接口入口补解密
loginBody.setPassword(passwordTransferCryptoService.decrypt(loginBody.getPassword()));
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
要求:
-
只改
/login -
不改
loginWithoutCaptcha -
解密失败直接抛错,不追加明文兼容分支
-
Step 4: 重新运行登录/注册测试
Run: mvn -pl ruoyi-admin -am -Dtest=SysLoginControllerPasswordTransferTest,SysRegisterControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: PASS
- Step 5: 提交本任务
git add ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysLoginControllerPasswordTransferTest.java ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysRegisterControllerPasswordTransferTest.java
git commit -m "接入登录注册密码解密"
Task 3: 接入个人修改密码接口解密
Files:
-
Modify:
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java -
Create:
ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysProfileControllerPasswordTransferTest.java -
Step 1: 写修改密码失败测试
mockMvc.perform(put("/system/user/profile/updatePwd")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"oldPassword\":\"oldCipher\",\"newPassword\":\"newCipher\"}"))
.andExpect(status().isOk());
verify(passwordTransferCryptoService).decrypt("oldCipher");
verify(passwordTransferCryptoService).decrypt("newCipher");
- Step 2: 运行测试确认失败
Run: mvn -pl ruoyi-admin -am -Dtest=SysProfileControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: FAIL,updatePwd 尚未解密 oldPassword、newPassword
- Step 3: 在
updatePwd开头显式解密两个字段
String oldPassword = passwordTransferCryptoService.decrypt(params.get("oldPassword"));
String newPassword = passwordTransferCryptoService.decrypt(params.get("newPassword"));
要求:
-
仅在解密成功后继续旧密码校验
-
不处理
confirmPassword -
保持原有报错文案和 BCrypt 入库逻辑
-
Step 4: 重新运行测试
Run: mvn -pl ruoyi-admin -am -Dtest=SysProfileControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: PASS
- Step 5: 提交本任务
git add ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysProfileControllerPasswordTransferTest.java
git commit -m "接入个人修改密码解密"
Task 4: 接入管理员新增用户与重置密码接口解密
Files:
-
Modify:
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java -
Create:
ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysUserControllerPasswordTransferTest.java -
Step 1: 写新增用户与重置密码失败测试
mockMvc.perform(post("/system/user")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"userName\":\"u1\",\"nickName\":\"n1\",\"deptId\":1,\"password\":\"cipher\"}"));
verify(passwordTransferCryptoService).decrypt("cipher");
mockMvc.perform(put("/system/user/resetPwd")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"userId\":2,\"password\":\"cipher\"}"));
verify(passwordTransferCryptoService).decrypt("cipher");
- Step 2: 运行测试确认失败
Run: mvn -pl ruoyi-admin -am -Dtest=SysUserControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: FAIL,新增用户和重置密码入口尚未调用解密
- Step 3: 在
add与resetPwd中先解密后继续原逻辑
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
要求:
-
仅对
add、resetPwd补解密 -
edit不动 -
仍保留现有权限校验与数据范围校验
-
Step 4: 重新运行测试
Run: mvn -pl ruoyi-admin -am -Dtest=SysUserControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: PASS
- Step 5: 提交本任务
git add ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysUserControllerPasswordTransferTest.java
git commit -m "接入用户密码接口解密"
Task 5: 汇总验证与后端实施记录
Files:
-
Create:
doc/implementation-report-2026-03-30-login-password-encryption-backend.md -
Step 1: 运行后端全部目标测试
Run: mvn -pl ruoyi-admin,ruoyi-framework -am -Dtest=PasswordTransferCryptoServiceTest,SysLoginControllerPasswordTransferTest,SysRegisterControllerPasswordTransferTest,SysProfileControllerPasswordTransferTest,SysUserControllerPasswordTransferTest -Dsurefire.failIfNoSpecifiedTests=false test
Expected: PASS,所有新增后端测试通过
- Step 2: 手工核对
/login/test未被改动
Run: git diff -- ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
Expected: 仅 /login 增加解密调用,loginWithoutCaptcha 无行为变化
- Step 3: 写后端实施记录
# 密码加密传输后端实施记录
- 新增密码解密服务
- 接入 5 个正式接口中的后端入口
- 保持 `/login/test` 不变
- 补充控制器与服务测试
- Step 4: 再次检查文档路径与 git 状态
Run: git status --short
Expected: 仅包含后端实现文件与 doc/implementation-report-2026-03-30-login-password-encryption-backend.md
- Step 5: 提交本任务
git add doc/implementation-report-2026-03-30-login-password-encryption-backend.md
git commit -m "完成密码加密传输后端实现"