# 登录验证码重构设计方案 ## 1. 背景与目标 ### 现状 当前登录使用滑块拖动验证,用户体验不够友好,且代码实现较为复杂(纯前端拖动逻辑 + 后端 token 校验)。 ### 目标 将滑块验证改为图形数字+字母验证码,提升用户体验,简化前端逻辑,保持后端安全校验流程不变。 ### 范围 - 前端:`txw-mhzc-web` 登录页面(passwordlogin.vue、phonelogin.vue) - 后端:`txw-sso` 服务新增验证码生成接口 --- ## 2. 验证码规格 | 项目 | 规格 | |------|------| | 字符集 | 数字 0-9 + 大小写字母 A-Z/a-z | | 长度 | 4 位 | | 样式 | 扭曲变形文字 + 干扰线/噪点 | | 图片尺寸 | 120 x 40 px | | 格式 | Base64 PNG | | 有效期 | Redis 存储,TTL 5 分钟 | | 校验 | uuid + 验证码内容联合校验 | --- ## 3. 数据流 ### 验证码获取流程 ``` 前端页面加载 → POST /sso/verify/captcha → 后端生成 uuid + 验证码内容 → 存入 Redis: captcha:{uuid} = 验证码内容, TTL 5min → 返回 { uuid, imageBase64 } → 前端渲染图片 ``` ### 登录流程 ``` 用户输入账号密码 + 验证码 → POST /sso/auth/login { username: "xxx", password: "xxx", captchaVerification: "uuid", captchaCode: "Kp7m" } → 后端校验 captcha:{uuid} == captchaCode → 校验通过后继续账号密码验证 ``` --- ## 4. 前端改动 ### 4.1 文件结构 | 文件 | 操作 | 说明 | |------|------|------| | `passwordlogin.vue` | 修改 | 注释滑块代码,新增验证码组件 | | `phonelogin.vue` | 修改 | 同上 | | `login.js` | 修改 | 新增 `getCaptcha()` API | ### 4.2 passwordlogin.vue 改动 **注释掉的代码(原滑块相关):** - `mouseDown`, `mouseMoveFn`, `moseUpFn`, `successFunction` 方法 → 注释 - `maxWidth`, `beginClientX`, `mouseMoveState`, `confirmWords`, `confirmSuccess` 数据 → 注释 - `.drag` 模板区域 → 注释,替换为新验证码区域 - `mounted()` 中滑块初始化逻辑 → 注释 - `beforeDestroy()` 中的清理逻辑 → 注释 **新增代码:** - 新增 `captchaCode` 表单字段 - 新增 `captchaUuid` 存储当前验证码 uuid - 新增 `captchaImage` 存储验证码图片 base64 - 新增 `getCaptcha()` 方法调用后端接口 - 新增 `refreshCaptcha()` 刷新验证码方法 - 模板新增验证码图片 + 输入框 + 刷新按钮区域 ### 4.3 验证码组件 UI(新增模板区域) ```html
刷新
``` ### 4.4 样式新增 ```css .captcha-container { display: flex; align-items: center; gap: 12px; } .captcha-img { width: 120px; height: 40px; cursor: pointer; border-radius: 4px; } .refresh-btn { color: #0052d9; cursor: pointer; font-size: 14px; } ``` ### 4.5 API 改动 **login.js 新增:** ```javascript // 获取图形验证码 export const getCaptcha = () => { return request({ url: '/sso/verify/captcha', method: 'post' }) } ``` --- ## 5. 后端改动 ### 5.1 文件结构 | 文件 | 操作 | 说明 | |------|------|------| | `VerifyController.java` | 修改 | 新增 `/verify/captcha` 接口 | | `VerifyService.java` | 修改 | 新增 `getCaptcha()` 接口定义 | | `VerifyServiceImpl.java` | 修改 | 实现验证码生成(使用 Hutool 的 CaptchaUtil) | | `AuthLoginReqVO.java` | 修改 | 新增 `captchaCode` 字段 | | `AuthServiceImpl.java` | 修改 | login() 方法新增验证码校验逻辑 | ### 5.2 接口定义 **POST /sso/verify/captcha** 请求: ```json { "remoteId": "IP+UserAgent hash" } ``` 响应: ```json { "code": 0, "data": { "uuid": "abc123...", "imageBase64": "data:image/png;base64,iVBORw0KGgo..." } } ``` ### 5.3 Redis 存储结构 | Key | Value | TTL | |-----|-------|-----| | `captcha:{uuid}` | 验证码内容(如 "Kp7m") | 5 分钟 | ### 5.4 登录接口改动 `AuthLoginReqVO` 新增字段: ```java private String captchaCode; // 用户输入的验证码 ``` `AuthServiceImpl.login()` 改动: ```java // 原有验证码 token 校验(滑块) verifyService.checkVerifyToken(reqVO.getCaptchaVerification()); // 新增图形验证码校验 verifyService.checkCaptcha(reqVO.getCaptchaVerification(), reqVO.getCaptchaCode()); ``` --- ## 6. 安全考虑 1. **防暴力破解**:验证码校验失败后不暴露具体错误原因("验证码错误" vs "验证码已过期") 2. **一次性**:验证码验证成功后立即从 Redis 删除 3. **限频**:同一 IP 请求验证码频率限制(TODO) 4. **混淆**:图形验证码使用扭曲字体 + 干扰线,防止简单 OCR --- ## 7. 兼容性 - 原滑块相关代码**注释保留**,不删除,便于后续回滚 - `captchaVerification` 字段保留(复用为 uuid),登录参数结构兼容 - 后端兼容旧版滑块 token 校验逻辑(captcha check 可配置开关) --- ## 8. 测试要点 1. 验证码图片正确渲染(扭曲字符可见) 2. 点击刷新生成新验证码 3. 输入正确验证码 + 正确账号密码 → 登录成功 4. 输入错误验证码 → 登录失败,提示"验证码错误" 5. 验证码过期(5分钟)→ 登录失败,提示"验证码已过期" 6. 滑块相关代码注释后,页面功能不受影响