将滑块验证改为数字+字母图形验证码,保持后端校验流程兼容。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.5 KiB
5.5 KiB
登录验证码重构设计方案
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(新增模板区域)
<t-form-item name="captchaCode">
<div class="captcha-container">
<img :src="captchaImage" @click="refreshCaptcha" class="captcha-img" />
<t-input
v-model="loginForm.captchaCode"
placeholder="请输入验证码"
maxlength="4"
style="width: 120px"
/>
<span class="refresh-btn" @click="refreshCaptcha">刷新</span>
</div>
</t-form-item>
4.4 样式新增
.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 新增:
// 获取图形验证码
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
请求:
{
"remoteId": "IP+UserAgent hash"
}
响应:
{
"code": 0,
"data": {
"uuid": "abc123...",
"imageBase64": "data:image/png;base64,iVBORw0KGgo..."
}
}
5.3 Redis 存储结构
| Key | Value | TTL |
|---|---|---|
captcha:{uuid} |
验证码内容(如 "Kp7m") | 5 分钟 |
5.4 登录接口改动
AuthLoginReqVO 新增字段:
private String captchaCode; // 用户输入的验证码
AuthServiceImpl.login() 改动:
// 原有验证码 token 校验(滑块)
verifyService.checkVerifyToken(reqVO.getCaptchaVerification());
// 新增图形验证码校验
verifyService.checkCaptcha(reqVO.getCaptchaVerification(), reqVO.getCaptchaCode());
6. 安全考虑
- 防暴力破解:验证码校验失败后不暴露具体错误原因("验证码错误" vs "验证码已过期")
- 一次性:验证码验证成功后立即从 Redis 删除
- 限频:同一 IP 请求验证码频率限制(TODO)
- 混淆:图形验证码使用扭曲字体 + 干扰线,防止简单 OCR
7. 兼容性
- 原滑块相关代码注释保留,不删除,便于后续回滚
captchaVerification字段保留(复用为 uuid),登录参数结构兼容- 后端兼容旧版滑块 token 校验逻辑(captcha check 可配置开关)
8. 测试要点
- 验证码图片正确渲染(扭曲字符可见)
- 点击刷新生成新验证码
- 输入正确验证码 + 正确账号密码 → 登录成功
- 输入错误验证码 → 登录失败,提示"验证码错误"
- 验证码过期(5分钟)→ 登录失败,提示"验证码已过期"
- 滑块相关代码注释后,页面功能不受影响