From 1d65e97b041052ad8efb33bda336be60a812b641 Mon Sep 17 00:00:00 2001 From: yuyx <237899745@qq.com> Date: Fri, 28 Nov 2025 13:11:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B3=A8=E5=86=8C=E3=80=81=E9=87=8D?= =?UTF-8?q?=E7=BD=AE=E5=AF=86=E7=A0=81=E3=80=81=E9=87=8D=E5=8F=91=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E9=82=AE=E4=BB=B6=E6=B7=BB=E5=8A=A0=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端修改: - 添加通用验证码验证函数 verifyCaptcha() - /api/register 接口添加验证码验证 - /api/password/forgot 接口添加验证码验证 - /api/resend-verification 接口添加验证码验证 前端修改: - 注册表单添加验证码输入框和图片 - 忘记密码模态框添加验证码 - 重发验证邮件区域添加验证码输入 - 添加各表单的验证码刷新方法 - 提交失败后自动刷新验证码 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/server.js | 76 ++++++++++++++++++++++++++++++++++++++++++++--- frontend/app.html | 29 +++++++++++++++--- frontend/app.js | 57 +++++++++++++++++++++++++++++++---- 3 files changed, 148 insertions(+), 14 deletions(-) diff --git a/backend/server.js b/backend/server.js index d4041d7..800303d 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1100,6 +1100,42 @@ function checkMailRateLimit(req, type = 'mail') { } } +// ===== 验证码验证辅助函数 ===== + +/** + * 验证验证码 + * @param {Object} req - 请求对象 + * @param {string} captcha - 用户输入的验证码 + * @returns {{valid: boolean, message?: string}} 验证结果 + */ +function verifyCaptcha(req, captcha) { + if (!captcha) { + return { valid: false, message: '请输入验证码' }; + } + + const sessionCaptcha = req.session.captcha; + const captchaTime = req.session.captchaTime; + + if (!sessionCaptcha || !captchaTime) { + return { valid: false, message: '验证码已过期,请刷新验证码' }; + } + + // 验证码有效期5分钟 + if (Date.now() - captchaTime > 5 * 60 * 1000) { + return { valid: false, message: '验证码已过期,请刷新验证码' }; + } + + if (captcha.toLowerCase() !== sessionCaptcha) { + return { valid: false, message: '验证码错误' }; + } + + // 验证通过后清除session中的验证码 + delete req.session.captcha; + delete req.session.captchaTime; + + return { valid: true }; +} + // ===== 公开API ===== // 健康检查 @@ -1164,7 +1200,8 @@ app.post('/api/register', .isLength({ min: 3, max: 20 }).withMessage('用户名长度3-20个字符') .matches(USERNAME_REGEX).withMessage('用户名仅允许中英文、数字、下划线、点和短横线'), body('email').isEmail().withMessage('邮箱格式不正确'), - body('password').isLength({ min: 6 }).withMessage('密码至少6个字符') + body('password').isLength({ min: 6 }).withMessage('密码至少6个字符'), + body('captcha').notEmpty().withMessage('请输入验证码') ], async (req, res) => { const errors = validationResult(req); @@ -1176,6 +1213,16 @@ app.post('/api/register', } try { + // 验证验证码 + const { captcha } = req.body; + const captchaResult = verifyCaptcha(req, captcha); + if (!captchaResult.valid) { + return res.status(400).json({ + success: false, + message: captchaResult.message + }); + } + checkMailRateLimit(req, 'verify'); const { username, email, password } = req.body; @@ -1263,7 +1310,8 @@ app.post('/api/resend-verification', [ body('username') .optional({ checkFalsy: true }) .isLength({ min: 3 }).withMessage('用户名格式不正确') - .matches(USERNAME_REGEX).withMessage('用户名仅允许中英文、数字、下划线、点和短横线') + .matches(USERNAME_REGEX).withMessage('用户名仅允许中英文、数字、下划线、点和短横线'), + body('captcha').notEmpty().withMessage('请输入验证码') ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { @@ -1271,6 +1319,16 @@ app.post('/api/resend-verification', [ } try { + // 验证验证码 + const { captcha } = req.body; + const captchaResult = verifyCaptcha(req, captcha); + if (!captchaResult.valid) { + return res.status(400).json({ + success: false, + message: captchaResult.message + }); + } + checkMailRateLimit(req, 'verify'); const { email, username } = req.body; @@ -1332,15 +1390,25 @@ app.get('/api/verify-email', async (req, res) => { // 发起密码重置(邮件) app.post('/api/password/forgot', [ - body('email').isEmail().withMessage('邮箱格式不正确') + body('email').isEmail().withMessage('邮箱格式不正确'), + body('captcha').notEmpty().withMessage('请输入验证码') ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success: false, errors: errors.array() }); } - const { email } = req.body; + const { email, captcha } = req.body; try { + // 验证验证码 + const captchaResult = verifyCaptcha(req, captcha); + if (!captchaResult.valid) { + return res.status(400).json({ + success: false, + message: captchaResult.message + }); + } + checkMailRateLimit(req, 'pwd_forgot'); const smtpConfig = getSmtpConfig(); diff --git a/frontend/app.html b/frontend/app.html index 78fbc48..7410130 100644 --- a/frontend/app.html +++ b/frontend/app.html @@ -1038,7 +1038,14 @@ 点击图片刷新验证码
- 邮箱未验证?点击重发激活邮件 +
邮箱未验证?请输入验证码后重发激活邮件
+
+ + + +
@@ -1049,7 +1056,7 @@ 登录 -
+
@@ -1062,6 +1069,13 @@
+
+ +
+ + +
+
@@ -2590,7 +2604,7 @@