# 登录验证码功能说明 ## 功能概述 本次更新为"玩玩云"云存储系统添加了登录验证码功能,提高了系统的安全性。该功能会在用户输错密码一定次数后自动显示验证码,要求用户输入验证码才能继续尝试登录。 ## 功能特性 ### 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 - 后端日志文件