# 系统登录与密码类接口加密传输设计文档

## 1. 背景

当前系统登录、注册、修改密码、重置密码、新增用户等正式接口，在请求体中直接传输明文密码。后端在收到密码后再执行现有的登录校验或 BCrypt 加密入库逻辑。

本次需求是在不改变现有业务语义的前提下，为所有正式密码提交接口增加“密码加密传输”能力，避免密码以明文形式直接出现在接口请求体中。

## 2. 已确认约束

- 采用对称加密方案
- 前端使用固定密钥加密密码字段
- 后端使用同一固定密钥解密密码字段
- 覆盖所有正式密码提交接口
- 明确不包含 `/login/test`
- 不新增兼容性或补丁性方案
- 不允许“解密失败后按明文继续处理”
- 保持最短路径实现，不改现有账号、认证、密码存储主逻辑

## 3. 接口范围

本次加密传输仅覆盖以下正式接口：

- `/login`
- `/register`
- `/system/user/profile/updatePwd`
- `/system/user/resetPwd`
- `/system/user`

各接口需要处理的密码字段如下：

- `/login`：`password`
- `/register`：`password`
- `/system/user/profile/updatePwd`：`oldPassword`、`newPassword`
- `/system/user/resetPwd`：`password`
- `/system/user`：`password`

以下接口不在本次范围内：

- `/login/test`
- 任何不提交密码字段的接口

## 4. 现状分析

### 4.1 前端现状

当前前端接口调用中，登录、注册、个人修改密码、管理员重置密码、管理员新增用户都直接提交明文密码字段。仓库中虽然已经存在 `JSEncrypt` 工具，但仅用于“记住密码”场景下 Cookie 的本地存储加密，并没有用于登录或其他正式密码接口。

### 4.2 后端现状

后端正式接口的密码处理链路如下：

- 登录接口直接读取 `LoginBody.password` 并交给认证流程
- 注册接口直接读取 `RegisterBody.password` 并执行 BCrypt 加密入库
- 修改密码接口直接读取 `oldPassword`、`newPassword` 并执行旧密码校验和新密码入库
- 管理员重置密码和新增用户接口直接读取 `SysUser.password` 并执行 BCrypt 加密

现有后端没有统一的密码传输解密层，因此如果直接在前端加密而后端不解密，现有校验链路会全部失效。

## 5. 方案对比

### 方案一：保留现有字段名，前端加密后提交，后端统一解密

做法：

- 保持现有请求结构不变
- 前端在 API 提交前仅加密密码字段
- 后端在控制器进入业务逻辑前，对密码字段统一解密

优点：

- 改动路径最短
- 页面、DTO、控制器入参结构基本不变
- 现有业务校验和 BCrypt 逻辑可直接复用

缺点：

- 需要明确每个接口的密码字段清单
- 前后端都要维护一份受控字段映射

### 方案二：新增专用密文字段

做法：

- 每个接口新增 `encryptedPassword`、`encryptedOldPassword` 等字段
- 后端只处理密文字段

优点：

- 语义清楚
- 明文和密文边界直观

缺点：

- 改动面大
- 前后端 DTO、表单、测试样例都要整体调整
- 不符合本次最短路径实现原则

### 方案三：全局请求拦截器加密 + 全局参数层解密

做法：

- 前端在 axios 拦截器中按 URL 自动加密密码字段
- 后端在过滤器或参数解析层统一自动解密

优点：

- 页面层改动最少

缺点：

- 隐式逻辑过重
- 对不同入参类型的接口可读性差
- 不利于后续定位问题

## 6. 设计结论

采用方案一。

本次仅在接口边界增加密码加密传输能力，业务层继续只处理解密后的明文密码。传输链路如下：

1. 前端表单收集用户输入的密码明文
2. API 提交前，使用固定对称密钥加密密码字段
3. 后端控制器收到请求后，先对约定密码字段解密
4. 解密成功后继续走现有业务逻辑
5. 解密失败时直接返回错误，不进入后续业务处理

`/login/test` 保持现状，不加入加密与解密逻辑。

## 7. 前端设计

### 7.1 设计目标

前端只负责“在请求发出前对密码字段加密”，不在页面组件中分散实现逻辑，也不修改表单字段命名。

### 7.2 收口位置

加密逻辑收口在 API 调用层，不放在页面组件层。

原因：

- 登录页、注册页、个人中心、用户管理都存在密码提交场景
- 若每个页面独立处理，加密逻辑容易分散和重复
- API 层更容易统一维护接口与字段映射

### 7.3 前端改动点

- 新增统一的对称加密工具
- 新增“密码字段加密”辅助方法
- 在以下接口调用前对对应字段加密：
  - 登录
  - 注册
  - 个人修改密码
  - 管理员重置密码
  - 管理员新增用户
- 保持请求字段名不变

### 7.4 配置方式

前端固定密钥通过环境配置读取，不直接散落在业务代码中。

## 8. 后端设计

### 8.1 设计目标

后端只负责“在进入现有业务逻辑前将密码字段解密为明文”，不改动现有认证和密码存储主流程。

### 8.2 收口位置

解密逻辑收口在控制器入口之后、业务逻辑之前，由统一的密码解密工具完成。

原因：

- 当前接口入参类型不统一，包含 `LoginBody`、`RegisterBody`、`SysUser` 和 `Map<String, String>`
- 如果直接放到全局过滤器或参数解析层，会增加隐式复杂度
- 控制器显式调用统一解密工具，路径更短、更直观

### 8.3 后端改动点

- 新增统一的对称解密工具
- 新增面向不同入参类型的密码字段解密方法
- 在以下正式接口进入业务逻辑前显式解密：
  - `SysLoginController.login`
  - `SysRegisterController.register`
  - `SysProfileController.updatePwd`
  - `SysUserController.resetPwd`
  - `SysUserController.add`
- 不改动 `SysLoginController.loginWithoutCaptcha`

### 8.4 业务链路保持不变

解密成功后继续沿用现有逻辑：

- 登录继续走认证管理器与 `SysPasswordService`
- 注册继续走 BCrypt 加密入库
- 个人修改密码继续先校验旧密码，再加密新密码入库
- 管理员重置密码和新增用户继续走 BCrypt 加密入库

## 9. 配置设计

前后端分别维护固定对称密钥配置：

- 前端从环境变量读取固定密钥
- 后端从 `application.yml` 读取固定密钥

本次设计默认前后端使用同一把固定密钥，不涉及动态下发、轮换或多套密钥管理。

## 10. 错误处理

本次只采用单一路径，不做兼容分支：

- 受控正式接口收到密码字段后，后端默认按密文处理
- 任一密码字段解密失败，接口直接返回错误
- 不允许“尝试解密失败后继续按明文处理”
- 不允许只加密部分密码字段后继续流转

修改密码接口中，`oldPassword` 与 `newPassword` 必须同时成功解密后才能进入现有校验流程。

## 11. 非目标

本次不包含以下内容：

- 不修改 `/login/test`
- 不改造密码存储方式
- 不改造现有 BCrypt 校验逻辑
- 不引入非对称加密
- 不增加密钥动态下发能力
- 不增加明密文双通道兼容逻辑
- 不修改与密码无关的请求字段

## 12. 风险与控制

主要风险如下：

1. 前后端固定密钥不一致，会导致所有正式密码接口失败
2. 某些密码字段漏加密或漏解密，会导致登录失败或入库异常
3. 个人修改密码接口包含多个密码字段，若字段映射错误，会导致旧密码校验失败

控制方式：

- 前后端统一约定固定密钥配置名称与用途
- 将密码字段清单明确写入实现计划
- 将正式接口逐一纳入测试验证
- 保持 `/login/test` 完全不接入，避免影响现有测试用途

## 13. 验证方案

实施后至少验证以下场景：

1. `/login` 提交加密后的 `password` 可以正常登录
2. `/register` 提交加密后的 `password` 可以正常注册
3. `/system/user/profile/updatePwd` 提交加密后的 `oldPassword`、`newPassword` 可以正常修改密码
4. `/system/user/resetPwd` 提交加密后的 `password` 可以正常重置密码
5. `/system/user` 提交加密后的 `password` 可以正常新增用户
6. 受控正式接口在密文非法时直接失败
7. `/login/test` 仍按现有方式运行，不受本次改动影响

## 14. 实施范围

- 前端：登录、注册、个人中心、用户管理相关 API 和密码加密工具
- 后端：登录、注册、个人中心、用户管理相关控制器和密码解密工具
- 配置：前端环境配置、后端应用配置
- 数据库：无表结构改动

本次属于接口边界增强，不涉及数据库结构和核心认证机制重构。
