Files
vue-driven-cloud-storage/CAPTCHA_FEATURE.md
喻勇祥 61c99ce5c0 添加登录验证码功能 - 增强系统安全性
## 新增功能
- 密码输错2次后自动显示验证码
- 4位数字验证码,点击可刷新
- 验证码有效期5分钟
- 基于IP和用户名双重防护
- 前台和后台登录均支持

## 后端改动
- 新增验证码生成API: GET /api/captcha
- 修改登录API支持验证码验证
- 添加session管理验证码
- 增强RateLimiter防爆破机制

## 前端改动
- 登录表单添加验证码输入框(条件显示)
- 验证码图片展示和刷新功能
- 自动触发验证码显示逻辑

## 依赖更新
- 新增: svg-captcha (验证码生成)
- 新增: express-session (session管理)

## 文档
- CAPTCHA_FEATURE.md - 详细功能文档
- CAPTCHA_README.md - 快速开始指南
- test_captcha.sh - 自动化测试脚本
- 更新说明_验证码功能.txt - 中文说明

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 16:32:32 +00:00

7.5 KiB
Raw Blame History

登录验证码功能说明

功能概述

本次更新为"玩玩云"云存储系统添加了登录验证码功能,提高了系统的安全性。该功能会在用户输错密码一定次数后自动显示验证码,要求用户输入验证码才能继续尝试登录。

功能特性

1. 智能验证码触发

  • 自动触发当用户输错密码2次后系统会自动显示验证码输入框
  • 适用范围:前台用户登录和后台管理员登录均适用
  • 双重保护基于IP地址和用户名两个维度进行失败次数统计

2. 验证码特点

  • 纯数字验证码4位数字易于识别和输入
  • 彩色显示:验证码图片使用彩色显示,提高可读性
  • 点击刷新:点击验证码图片即可刷新获取新的验证码
  • 有效期限验证码有效期为5分钟过期后需要刷新
  • 安全存储验证码存储在服务器端session中防止客户端篡改

3. 防爆破机制

  • 失败限制15分钟内失败5次将被封锁30分钟
  • 渐进式保护
    • 第1-2次失败仅提示密码错误
    • 第3-5次失败显示验证码要求输入
    • 第5次失败封锁IP和用户名30分钟

技术实现

后端改动

1. 新增依赖

  • svg-captcha: 用于生成SVG格式的验证码图片
  • express-session: 用于管理session存储验证码

2. 新增API端点

GET /api/captcha
  • 功能生成并返回SVG格式的验证码图片
  • 返回SVG图片数据
  • Session存储验证码文本和生成时间

3. 修改登录API

POST /api/login

新增参数:

  • captcha (可选): 验证码输入值

验证逻辑:

  1. 检查IP和用户名的失败次数
  2. 如果失败次数 >= 2则要求提供验证码
  3. 验证验证码的有效性(是否存在、是否过期、是否正确)
  4. 验证码错误返回 needCaptcha: true

4. RateLimiter增强

  • 新增 getFailureCount() 方法获取指定key的失败次数
  • recordFailure() 返回值新增 needCaptcha 字段

前端改动

1. 数据字段

新增:

showCaptcha: false,      // 是否显示验证码
captchaUrl: '',          // 验证码图片URL
loginForm.captcha: ''    // 验证码输入值

2. UI组件

在登录表单中添加:

  • 验证码输入框(条件显示)
  • 验证码图片显示区域
  • 点击刷新提示文字

3. 逻辑方法

新增 refreshCaptcha() 方法:

refreshCaptcha() {
  this.captchaUrl = `${this.apiBase}/api/captcha?t=${Date.now()}`;
}

修改 handleLogin() 方法:

  • 登录失败时检查 response.data.needCaptcha
  • 如果需要验证码,显示验证码并调用 refreshCaptcha()
  • 登录成功后隐藏验证码并清空输入

使用说明

用户使用流程

  1. 首次登录尝试

    • 输入用户名和密码
    • 点击"登录"按钮
    • 如果密码错误,会提示"用户名或密码错误"
  2. 第三次登录尝试(触发验证码)

    • 输入用户名和密码
    • 系统自动显示验证码输入框
    • 输入图片中显示的4位数字
    • 如果看不清,点击图片刷新验证码
    • 点击"登录"按钮
  3. 验证码验证

    • 如果验证码错误,会提示"验证码错误",验证码会自动刷新
    • 如果验证码过期,会提示"验证码已过期,请刷新验证码"
    • 验证码正确且密码正确,登录成功
  4. 账号封锁

    • 如果连续失败5次账号将被封锁30分钟
    • 封锁期间尝试登录会提示"账号已被封禁"

管理员说明

管理员登录时同样受到验证码保护,流程与普通用户完全一致。

配置说明

Session配置

backend/server.js 中配置session

app.use(session({
  secret: process.env.SESSION_SECRET || 'your-session-secret-change-in-production',
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.COOKIE_SECURE === 'true',
    httpOnly: true,
    maxAge: 10 * 60 * 1000 // 10分钟
  }
}));

建议在 .env 文件中设置:

SESSION_SECRET=你的session密钥

验证码参数

backend/server.js 的验证码生成代码中可调整:

const captcha = svgCaptcha.create({
  size: 4,                // 验证码长度4位数字
  noise: 2,               // 干扰线条数
  color: true,            // 使用彩色
  background: '#f0f0f0',  // 背景色
  width: 120,             // 宽度
  height: 40,             // 高度
  fontSize: 50,           // 字体大小
  charPreset: '0123456789' // 只使用数字
});

防爆破参数

backend/server.js 中配置RateLimiter

const loginLimiter = new RateLimiter({
  maxAttempts: 5,                // 最大失败次数
  windowMs: 15 * 60 * 1000,      // 统计窗口15分钟
  blockDuration: 30 * 60 * 1000  // 封锁时长30分钟
});

验证码触发阈值在登录逻辑中设置:

const needCaptcha = ipFailures >= 2 || usernameFailures >= 2;

可以修改 >= 2 来调整触发次数。

安全建议

  1. 设置SESSION_SECRET

    • 在生产环境中务必设置强随机的SESSION_SECRET
    • 使用 node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" 生成
  2. 启用HTTPS

    • 在生产环境中设置 COOKIE_SECURE=true
    • 确保使用HTTPS协议
  3. 定期审计

    • 定期检查登录失败日志
    • 关注异常的登录尝试
  4. 调整参数

    • 根据实际使用情况调整失败次数阈值
    • 根据用户反馈调整验证码难度

测试方法

测试验证码显示

  1. 启动服务器:cd backend && node server.js
  2. 访问登录页面
  3. 使用错误的用户名或密码登录2次
  4. 第3次尝试时应该看到验证码输入框

测试验证码API

curl "http://localhost:40001/api/captcha" > test.svg

查看生成的 test.svg 文件应该显示一个4位数字的验证码。

测试登录流程

# 第一次失败(无验证码)
curl -X POST http://localhost:40001/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"wrong"}'

# 第二次失败(无验证码)
curl -X POST http://localhost:40001/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"wrong"}'

# 第三次失败(需要验证码)
curl -X POST http://localhost:40001/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"wrong"}'
# 返回: {"success":false,"message":"请输入验证码","needCaptcha":true}

故障排查

问题1验证码不显示

可能原因

  • Session未正确配置
  • 前端未正确接收 needCaptcha 标志

解决方法

  • 检查浏览器控制台是否有错误
  • 检查后端日志是否有session相关错误
  • 确认 express-session 依赖已安装

问题2验证码一直提示错误

可能原因

  • Session未持久化
  • 验证码大小写不匹配

解决方法

  • 验证码已统一转换为小写进行比较
  • 检查浏览器是否禁用了Cookie

问题3验证码图片不加载

可能原因

  • CORS配置问题
  • API路径错误

解决方法

  • 检查 ALLOWED_ORIGINS 环境变量配置
  • 确认API基础路径配置正确

更新日志

版本1.1.0

  • 新增登录验证码功能
  • 密码错误2次后自动显示验证码
  • 支持点击刷新验证码
  • 验证码有效期5分钟
  • 前台和后台登录均支持

技术支持

如有问题,请查看:

  • 项目README.md
  • GitHub Issues
  • 后端日志文件