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

281 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 登录验证码功能说明
## 功能概述
本次更新为"玩玩云"云存储系统添加了登录验证码功能,提高了系统的安全性。该功能会在用户输错密码一定次数后自动显示验证码,要求用户输入验证码才能继续尝试登录。
## 功能特性
### 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. 数据字段
新增:
```javascript
showCaptcha: false, // 是否显示验证码
captchaUrl: '', // 验证码图片URL
loginForm.captcha: '' // 验证码输入值
```
#### 2. UI组件
在登录表单中添加:
- 验证码输入框(条件显示)
- 验证码图片显示区域
- 点击刷新提示文字
#### 3. 逻辑方法
新增 `refreshCaptcha()` 方法:
```javascript
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
```javascript
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` 的验证码生成代码中可调整:
```javascript
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
```javascript
const loginLimiter = new RateLimiter({
maxAttempts: 5, // 最大失败次数
windowMs: 15 * 60 * 1000, // 统计窗口15分钟
blockDuration: 30 * 60 * 1000 // 封锁时长30分钟
});
```
**验证码触发阈值**在登录逻辑中设置:
```javascript
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
```bash
curl "http://localhost:40001/api/captcha" > test.svg
```
查看生成的 test.svg 文件应该显示一个4位数字的验证码。
### 测试登录流程
```bash
# 第一次失败(无验证码)
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
- 后端日志文件