txw/docs/superpowers/specs/2026-04-15-login-captcha-design.md
liulujian 880006db5a docs: 添加登录验证码重构设计方案
将滑块验证改为数字+字母图形验证码,保持后端校验流程兼容。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 15:22:47 +08:00

5.5 KiB
Raw Blame History

登录验证码重构设计方案

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. 安全考虑

  1. 防暴力破解:验证码校验失败后不暴露具体错误原因("验证码错误" vs "验证码已过期"
  2. 一次性:验证码验证成功后立即从 Redis 删除
  3. 限频:同一 IP 请求验证码频率限制TODO
  4. 混淆:图形验证码使用扭曲字体 + 干扰线,防止简单 OCR

7. 兼容性

  • 原滑块相关代码注释保留,不删除,便于后续回滚
  • captchaVerification 字段保留(复用为 uuid登录参数结构兼容
  • 后端兼容旧版滑块 token 校验逻辑captcha check 可配置开关)

8. 测试要点

  1. 验证码图片正确渲染(扭曲字符可见)
  2. 点击刷新生成新验证码
  3. 输入正确验证码 + 正确账号密码 → 登录成功
  4. 输入错误验证码 → 登录失败,提示"验证码错误"
  5. 验证码过期5分钟→ 登录失败,提示"验证码已过期"
  6. 滑块相关代码注释后,页面功能不受影响