Files
loan-pricing/docs/superpowers/plans/2026-03-30-login-password-encryption-backend-plan.md

10 KiB
Raw Blame History

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: FAILupdatePwd 尚未解密 oldPasswordnewPassword

  • 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: 在 addresetPwd 中先解密后继续原逻辑
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));

要求:

  • 仅对 addresetPwd 补解密

  • 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 "完成密码加密传输后端实现"