const express = require('express') const router = express.Router() const { getDB } = require('../database') const Dysmsapi20170525 = require('@alicloud/dysmsapi20170525') const OpenApi = require('@alicloud/openapi-client') const { Config } = require('@alicloud/openapi-client') // 阿里云短信配置 const config = new Config({ // 您的AccessKey ID accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID || 'your_access_key_id', // 您的AccessKey Secret accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET || 'your_access_key_secret', // 访问的域名 endpoint: 'dysmsapi.aliyuncs.com' }) // 创建短信客户端 const client = new Dysmsapi20170525.default(config) // 短信模板配置 const SMS_CONFIG = { signName: process.env.ALIYUN_SMS_SIGN_NAME || '您的签名', // 短信签名 templateCode: process.env.ALIYUN_SMS_TEMPLATE_CODE || 'SMS_XXXXXX', // 短信模板CODE // 开发环境标识 isDevelopment: process.env.NODE_ENV !== 'production' } // 存储验证码的内存对象(生产环境建议使用Redis) const smsCodeStore = new Map() // 验证码有效期(5分钟) const CODE_EXPIRE_TIME = 5 * 60 * 1000 // 最大尝试次数 const MAX_ATTEMPTS = 3 // 发送频率限制(60秒) const SEND_INTERVAL = 60 * 1000 /** * 生成6位数字验证码 * @returns {string} 验证码 */ function generateSMSCode() { return Math.floor(100000 + Math.random() * 900000).toString(); } router.post('/send', async (req, res) => { try { const { phone } = req.body console.log(phone) // 验证手机号格式 const phoneRegex = /^1[3-9]\d{9}$/ if (!phoneRegex.test(phone)) { return res.json({ success: false, message: '手机号格式不正确' }) } // 检查发送频率限制 const lastSendTime = smsCodeStore.get(`last_send_${phone}`) if (lastSendTime && Date.now() - lastSendTime < SEND_INTERVAL) { const remainingTime = Math.ceil((SEND_INTERVAL - (Date.now() - lastSendTime)) / 1000) return res.json({ success: false, message: `请等待${remainingTime}秒后再发送` }) } // 生成6位数字验证码 const code = Math.random().toString().slice(-6) // 存储验证码信息 smsCodeStore.set(phone, { code, timestamp: Date.now(), attempts: 0 }) // 记录发送时间 smsCodeStore.set(`last_send_${phone}`, Date.now()) // 生产环境发送真实短信 try { console.log(code); const sendSmsRequest = new Dysmsapi20170525.SendSmsRequest({ phoneNumbers: phone, signName: SMS_CONFIG.signName, templateCode: SMS_CONFIG.templateCode, templateParam: JSON.stringify({ code }) }) const response = await client.sendSms(sendSmsRequest) console.log(response.body); if (response.body.code === 'OK') { res.json({ success: true, message: '验证码发送成功' }) } else { console.error('阿里云短信发送失败:', response.body) res.json({ success: false, message: '发送失败,请稍后重试' }) } } catch (smsError) { console.error('阿里云短信API调用失败:', smsError) res.json({ success: false, message: '发送失败,请稍后重试' }) } } catch (error) { console.error('发送短信验证码失败:', error) res.status(500).json({ success: false, message: '发送失败,请稍后重试' }) } }); /** * 导出验证手机号的函数供其他模块使用 * @param {string} phone 手机号 * @param {string} code 验证码 * @returns {boolean} 验证结果 */ function verifySMSCode(phone, code) { const storedData = smsCodeStore.get(phone); if (!storedData) { return false; } // 检查是否过期 if (Date.now() - storedData.timestamp > 300000) { smsCodeStore.delete(phone); return false; } // 检查尝试次数 if (storedData.attempts >= 3) { smsCodeStore.delete(phone); return false; } // 验证验证码 if (storedData.code === code) { smsCodeStore.delete(phone); smsCodeStore.delete(`time_${phone}`); return true; } return false; } // 清理过期验证码的定时任务 setInterval(() => { const now = Date.now(); for (const [key, value] of smsCodeStore.entries()) { if (key.startsWith('time_')) continue; if (value.timestamp && now - value.timestamp > 300000) { smsCodeStore.delete(key); smsCodeStore.delete(`time_${key}`); } } }, 60000); // 每分钟清理一次 module.exports = router; module.exports.verifySMSCode = verifySMSCode;