From 7ce9d95d440910202e2f071a3b561e969fb1e73d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=BB=E5=8B=87=E7=A5=A5?= <237899745@qq.com> Date: Fri, 21 Nov 2025 16:39:38 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81Session=E9=97=AE=E9=A2=98=20-=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E8=BF=87=E6=9C=9FBug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 问题描述 用户输入验证码后一直提示"验证码已过期" ## 根本原因 Session配置问题导致验证码无法正确保存和读取: 1. saveUninitialized: false 导致验证码请求时session不会被创建 2. 缺少 sameSite 属性导致某些情况下cookie无法正确传递 ## 修复方案 ### Session配置优化 - saveUninitialized: false → true (确保验证码请求时创建session) - 添加 name: 'captcha.sid' (自定义session cookie名称) - 添加 sameSite: 'lax' (防止CSRF同时确保同站请求携带cookie) ### 验证码生成API增强 - 添加 req.session.save() 确保session立即保存 - 添加调试日志输出SessionID和验证码内容 ### 登录API调试 - 添加详细的验证码验证日志 - 输出SessionID、失败次数、验证码匹配情况 - 帮助快速定位问题 ## 测试建议 1. 清除浏览器Cookie 2. 输错密码2次触发验证码 3. 查看后端日志确认SessionID一致 4. 输入正确验证码应该能通过验证 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/server.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/backend/server.js b/backend/server.js index bf732a2..d384d61 100644 --- a/backend/server.js +++ b/backend/server.js @@ -75,10 +75,12 @@ app.use(cookieParser()); app.use(session({ secret: process.env.SESSION_SECRET || 'your-session-secret-change-in-production', resave: false, - saveUninitialized: false, + saveUninitialized: true, // 改为true,确保验证码请求时创建session + name: 'captcha.sid', // 自定义session cookie名称 cookie: { secure: process.env.COOKIE_SECURE === 'true', httpOnly: true, + sameSite: 'lax', // 添加sameSite属性 maxAge: 10 * 60 * 1000 // 10分钟 } })); @@ -612,6 +614,15 @@ app.get('/api/captcha', (req, res) => { req.session.captcha = captcha.text.toLowerCase(); req.session.captchaTime = Date.now(); + // 保存session + req.session.save((err) => { + if (err) { + console.error('[验证码] Session保存失败:', err); + } else { + console.log('[验证码] 生成成功, SessionID:', req.sessionID, '验证码:', captcha.text); + } + }); + res.type('svg'); res.send(captcha.data); } catch (error) { @@ -708,6 +719,8 @@ app.post('/api/login', // 如果需要验证码,则验证验证码 if (needCaptcha) { + console.log('[登录验证] 需要验证码, SessionID:', req.sessionID, 'IP失败次数:', ipFailures, '用户名失败次数:', usernameFailures); + if (!captcha) { return res.status(400).json({ success: false, @@ -720,7 +733,10 @@ app.post('/api/login', const sessionCaptcha = req.session.captcha; const captchaTime = req.session.captchaTime; + console.log('[登录验证] Session验证码:', sessionCaptcha, '输入验证码:', captcha, 'Session时间:', captchaTime); + if (!sessionCaptcha || !captchaTime) { + console.log('[登录验证] 验证码不存在于Session中'); return res.status(400).json({ success: false, message: '验证码已过期,请刷新验证码', @@ -730,6 +746,7 @@ app.post('/api/login', // 验证码有效期5分钟 if (Date.now() - captchaTime > 5 * 60 * 1000) { + console.log('[登录验证] 验证码已超过5分钟'); return res.status(400).json({ success: false, message: '验证码已过期,请刷新验证码', @@ -738,6 +755,7 @@ app.post('/api/login', } if (captcha.toLowerCase() !== sessionCaptcha) { + console.log('[登录验证] 验证码不匹配'); return res.status(400).json({ success: false, message: '验证码错误', @@ -745,6 +763,7 @@ app.post('/api/login', }); } + console.log('[登录验证] 验证码验证通过'); // 验证通过后清除session中的验证码 delete req.session.captcha; delete req.session.captchaTime;