1
This commit is contained in:
@@ -6,7 +6,6 @@
|
|||||||
const Framework = require("../../framework/node-core-framework.js");
|
const Framework = require("../../framework/node-core-framework.js");
|
||||||
const dayjs = require('dayjs');
|
const dayjs = require('dayjs');
|
||||||
const email_service = require('../services/email_service.js');
|
const email_service = require('../services/email_service.js');
|
||||||
const redis = require('../../middleware/redis_proxy');
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
@@ -361,7 +360,7 @@ module.exports = {
|
|||||||
const email_normalized = email.toLowerCase().trim();
|
const email_normalized = email.toLowerCase().trim();
|
||||||
|
|
||||||
// 验证验证码
|
// 验证验证码
|
||||||
const emailVerifyResult = await verifyEmailCode(email_normalized, email_code);
|
const emailVerifyResult = await email_service.verifyEmailCode(email_normalized, email_code);
|
||||||
if (!emailVerifyResult.success) {
|
if (!emailVerifyResult.success) {
|
||||||
return ctx.fail(emailVerifyResult.message || '验证码错误或已过期');
|
return ctx.fail(emailVerifyResult.message || '验证码错误或已过期');
|
||||||
}
|
}
|
||||||
@@ -510,7 +509,7 @@ module.exports = {
|
|||||||
* description: 发送成功
|
* description: 发送成功
|
||||||
*/
|
*/
|
||||||
'POST /invite/send_email_code': async (ctx) => {
|
'POST /invite/send_email_code': async (ctx) => {
|
||||||
|
try {
|
||||||
const body = ctx.getBody();
|
const body = ctx.getBody();
|
||||||
const { email } = body;
|
const { email } = body;
|
||||||
|
|
||||||
@@ -528,7 +527,7 @@ module.exports = {
|
|||||||
const email_normalized = email.toLowerCase().trim();
|
const email_normalized = email.toLowerCase().trim();
|
||||||
|
|
||||||
// 发送验证码
|
// 发送验证码
|
||||||
const emailResult = await sendEmailCode(email_normalized);
|
const emailResult = await email_service.sendEmailCode(email_normalized);
|
||||||
if (!emailResult.success) {
|
if (!emailResult.success) {
|
||||||
return ctx.fail(emailResult.message || '发送验证码失败');
|
return ctx.fail(emailResult.message || '发送验证码失败');
|
||||||
}
|
}
|
||||||
@@ -536,166 +535,10 @@ module.exports = {
|
|||||||
return ctx.success({
|
return ctx.success({
|
||||||
message: '验证码已发送',
|
message: '验证码已发送',
|
||||||
expire_time: emailResult.expire_time || 300 // 默认5分钟过期
|
expire_time: emailResult.expire_time || 300 // 默认5分钟过期
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送验证码
|
|
||||||
* @param {string} email 邮箱地址
|
|
||||||
* @returns {Promise<{success: boolean, message?: string, expire_time?: number}>}
|
|
||||||
*/
|
|
||||||
async function sendEmailCode(email) {
|
|
||||||
try {
|
|
||||||
// 获取框架的 Redis 服务
|
|
||||||
|
|
||||||
|
|
||||||
// 统一邮箱地址为小写,避免大小写不一致导致的问题
|
|
||||||
const email_lower = email.toLowerCase().trim();
|
|
||||||
|
|
||||||
// 生成6位随机验证码
|
|
||||||
const code = Math.floor(100000 + Math.random() * 900000).toString();
|
|
||||||
|
|
||||||
// Redis key
|
|
||||||
const redis_key = `email_code:${email_lower}`;
|
|
||||||
|
|
||||||
// 验证码数据
|
|
||||||
const code_data = {
|
|
||||||
code: code,
|
|
||||||
created_at: Date.now()
|
|
||||||
};
|
|
||||||
|
|
||||||
// 存储到 Redis,设置 5 分钟过期时间(300秒)
|
|
||||||
try {
|
|
||||||
await redis.set(redis_key, JSON.stringify(code_data), 300);
|
|
||||||
} catch (redis_error) {
|
|
||||||
console.error(`[邮箱验证] Redis 存储失败: ${email_lower}`, redis_error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: '验证码存储失败,请稍后重试'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[邮箱验证] 生成验证码: ${email_lower} -> ${code}, 已存储到 Redis (5分钟过期)`);
|
|
||||||
|
|
||||||
// 调用邮件服务发送验证码
|
|
||||||
const email_result = await email_service.send_verification_code(email_lower, code);
|
|
||||||
|
|
||||||
if (!email_result.success) {
|
|
||||||
// 如果邮件发送失败,删除已生成的验证码
|
|
||||||
try {
|
|
||||||
await redis.del(redis_key);
|
|
||||||
} catch (del_error) {
|
|
||||||
console.error(`[邮箱验证] 删除验证码失败:`, del_error);
|
|
||||||
}
|
|
||||||
console.error(`[邮箱验证] 邮件发送失败,已删除验证码: ${email_lower}`);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: email_result.message || '发送验证码失败'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[邮箱验证] 验证码已发送到 ${email_lower}: ${code} (5分钟内有效)`);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
expire_time: 300
|
|
||||||
};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送验证码失败:', error);
|
console.error('发送验证码失败:', error);
|
||||||
return {
|
return ctx.fail('发送验证码失败: ' + error.message);
|
||||||
success: false,
|
|
||||||
message: error.message || '发送验证码失败'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证验证码
|
|
||||||
* @param {string} email 邮箱地址
|
|
||||||
* @param {string} code 验证码
|
|
||||||
* @returns {Promise<{success: boolean, message?: string}>}
|
|
||||||
*/
|
|
||||||
async function verifyEmailCode(email, code) {
|
|
||||||
try {
|
|
||||||
// 获取框架的 Redis 服务
|
|
||||||
const redis = Framework.getServices().redisService;
|
|
||||||
|
|
||||||
// 统一邮箱地址为小写,避免大小写不一致导致的问题
|
|
||||||
const email_lower = email.toLowerCase().trim();
|
|
||||||
|
|
||||||
console.log(`[邮箱验证] 开始验证: ${email_lower}, 验证码: ${code}`);
|
|
||||||
|
|
||||||
// Redis key
|
|
||||||
const redis_key = `email_code:${email_lower}`;
|
|
||||||
|
|
||||||
// 从 Redis 获取验证码
|
|
||||||
let cached_str;
|
|
||||||
try {
|
|
||||||
cached_str = await redis.get(redis_key);
|
|
||||||
} catch (redis_error) {
|
|
||||||
console.error(`[邮箱验证] Redis 获取失败:`, redis_error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: '验证码获取失败,请稍后重试'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
if (!cached_str) {
|
|
||||||
console.log(`[邮箱验证] 未找到该邮箱的验证码: ${email_lower}`);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: '验证码不存在或已过期,请重新获取'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析验证码数据
|
|
||||||
let cached;
|
|
||||||
try {
|
|
||||||
cached = JSON.parse(cached_str);
|
|
||||||
} catch (parse_error) {
|
|
||||||
console.error(`[邮箱验证] 解析验证码数据失败:`, parse_error);
|
|
||||||
try {
|
|
||||||
await redis.del(redis_key);
|
|
||||||
} catch (del_error) {
|
|
||||||
console.error(`[邮箱验证] 删除异常数据失败:`, del_error);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: '验证码数据异常,请重新获取'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[邮箱验证] 找到验证码,创建时间: ${new Date(cached.created_at).toLocaleString()}`);
|
|
||||||
|
|
||||||
// 验证码是否正确
|
|
||||||
if (cached.code !== code) {
|
|
||||||
console.log(`[邮箱验证] 验证码错误,期望: ${cached.code}, 实际: ${code}`);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: '验证码错误'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证成功后删除缓存
|
|
||||||
try {
|
|
||||||
await redis.del(redis_key);
|
|
||||||
} catch (del_error) {
|
|
||||||
console.error(`[邮箱验证] 删除验证码失败:`, del_error);
|
|
||||||
}
|
|
||||||
console.log(`[邮箱验证] 验证成功: ${email_lower}`);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('验证验证码失败:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: error.message || '验证失败'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* 从 Framework 获取 redisService
|
* 从 Framework 获取 redisService
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const Framework = require("../framework/node-core-framework.js");
|
const Framework = require("../../framework/node-core-framework.js");
|
||||||
|
|
||||||
module.exports = new Proxy({}, {
|
module.exports = new Proxy({}, {
|
||||||
get(_, prop) {
|
get(_, prop) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
const nodemailer = require('nodemailer');
|
const nodemailer = require('nodemailer');
|
||||||
const config = require('../../config/config.js');
|
const config = require('../../config/config.js');
|
||||||
|
const redis = require('../middleware/redis_proxy');
|
||||||
|
|
||||||
// 创建邮件传输器
|
// 创建邮件传输器
|
||||||
let transporter = null;
|
let transporter = null;
|
||||||
@@ -58,7 +59,7 @@ async function send_email(options) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有配置邮箱账号,返回错误
|
// 检查邮箱配置
|
||||||
const email_config = config.email || {};
|
const email_config = config.email || {};
|
||||||
if (!email_config.auth || !email_config.auth.user || !email_config.auth.pass) {
|
if (!email_config.auth || !email_config.auth.user || !email_config.auth.pass) {
|
||||||
console.warn('[邮件服务] QQ邮箱未配置,使用模拟发送');
|
console.warn('[邮件服务] QQ邮箱未配置,使用模拟发送');
|
||||||
@@ -182,8 +183,165 @@ async function send_verification_code(email, code) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送验证码(包含生成、存储和发送)
|
||||||
|
* @param {string} email 邮箱地址
|
||||||
|
* @returns {Promise<{success: boolean, message?: string, expire_time?: number}>}
|
||||||
|
*/
|
||||||
|
async function sendEmailCode(email) {
|
||||||
|
try {
|
||||||
|
// 统一邮箱地址为小写,避免大小写不一致导致的问题
|
||||||
|
const email_lower = email.toLowerCase().trim();
|
||||||
|
|
||||||
|
// 生成6位随机验证码
|
||||||
|
const code = Math.floor(100000 + Math.random() * 900000).toString();
|
||||||
|
|
||||||
|
// Redis key(包含邮箱地址,确保每个用户独立的验证码)
|
||||||
|
const redis_key = `email_code:${email_lower}`;
|
||||||
|
|
||||||
|
// 验证码数据
|
||||||
|
const code_data = {
|
||||||
|
code: code,
|
||||||
|
created_at: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 存储到 Redis,设置 5 分钟过期时间(300秒)
|
||||||
|
// 先获取 Redis 服务实例,确保在整个函数中使用同一个连接
|
||||||
|
const redis_service = redis;
|
||||||
|
try {
|
||||||
|
await redis_service.set(redis_key, JSON.stringify(code_data), 300);
|
||||||
|
} catch (redis_error) {
|
||||||
|
console.error(`[邮箱验证] Redis 存储失败: ${email_lower}`, redis_error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: '验证码存储失败,请稍后重试'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[邮箱验证] 生成验证码: ${email_lower} -> ${code}, 已存储到 Redis (5分钟过期)`);
|
||||||
|
|
||||||
|
// 调用邮件服务发送验证码
|
||||||
|
const email_result = await send_verification_code(email_lower, code);
|
||||||
|
|
||||||
|
if (!email_result.success) {
|
||||||
|
// 如果邮件发送失败,删除已生成的验证码
|
||||||
|
try {
|
||||||
|
await redis_service.del(redis_key);
|
||||||
|
} catch (del_error) {
|
||||||
|
console.error(`[邮箱验证] 删除验证码失败:`, del_error);
|
||||||
|
}
|
||||||
|
console.error(`[邮箱验证] 邮件发送失败,已删除验证码: ${email_lower}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: email_result.message || '发送验证码失败'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[邮箱验证] 验证码已发送到 ${email_lower}: ${code} (5分钟内有效)`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
expire_time: 300
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('发送验证码失败:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: error.message || '发送验证码失败'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证验证码
|
||||||
|
* @param {string} email 邮箱地址
|
||||||
|
* @param {string} code 验证码
|
||||||
|
* @returns {Promise<{success: boolean, message?: string}>}
|
||||||
|
*/
|
||||||
|
async function verifyEmailCode(email, code) {
|
||||||
|
try {
|
||||||
|
// 统一邮箱地址为小写,避免大小写不一致导致的问题
|
||||||
|
const email_lower = email.toLowerCase().trim();
|
||||||
|
|
||||||
|
console.log(`[邮箱验证] 开始验证: ${email_lower}, 验证码: ${code}`);
|
||||||
|
|
||||||
|
// Redis key(包含邮箱地址,确保每个用户独立的验证码)
|
||||||
|
const redis_key = `email_code:${email_lower}`;
|
||||||
|
|
||||||
|
// 从 Redis 获取验证码
|
||||||
|
// 先获取 Redis 服务实例,确保在整个函数中使用同一个连接
|
||||||
|
const redis_service = redis;
|
||||||
|
let cached_str;
|
||||||
|
try {
|
||||||
|
cached_str = await redis_service.get(redis_key);
|
||||||
|
} catch (redis_error) {
|
||||||
|
console.error(`[邮箱验证] Redis 获取失败:`, redis_error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: '验证码获取失败,请稍后重试'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cached_str) {
|
||||||
|
console.log(`[邮箱验证] 未找到该邮箱的验证码: ${email_lower}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: '验证码不存在或已过期,请重新获取'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析验证码数据
|
||||||
|
let cached;
|
||||||
|
try {
|
||||||
|
cached = JSON.parse(cached_str);
|
||||||
|
} catch (parse_error) {
|
||||||
|
console.error(`[邮箱验证] 解析验证码数据失败:`, parse_error);
|
||||||
|
try {
|
||||||
|
await redis_service.del(redis_key);
|
||||||
|
} catch (del_error) {
|
||||||
|
console.error(`[邮箱验证] 删除异常数据失败:`, del_error);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: '验证码数据异常,请重新获取'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[邮箱验证] 找到验证码,创建时间: ${new Date(cached.created_at).toLocaleString()}`);
|
||||||
|
|
||||||
|
// 验证码是否正确
|
||||||
|
if (cached.code !== code) {
|
||||||
|
console.log(`[邮箱验证] 验证码错误,期望: ${cached.code}, 实际: ${code}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: '验证码错误'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证成功后删除缓存
|
||||||
|
try {
|
||||||
|
await redis_service.del(redis_key);
|
||||||
|
} catch (del_error) {
|
||||||
|
console.error(`[邮箱验证] 删除验证码失败:`, del_error);
|
||||||
|
}
|
||||||
|
console.log(`[邮箱验证] 验证成功: ${email_lower}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('验证验证码失败:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: error.message || '验证失败'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
send_email,
|
send_email,
|
||||||
send_verification_code,
|
send_verification_code,
|
||||||
|
sendEmailCode,
|
||||||
|
verifyEmailCode,
|
||||||
init_transporter
|
init_transporter
|
||||||
};
|
};
|
||||||
|
|||||||
9
app.js
9
app.js
@@ -6,7 +6,7 @@
|
|||||||
const frameworkConfig = require('./config/framework.config.js')
|
const frameworkConfig = require('./config/framework.config.js')
|
||||||
const Framework = require('./framework/node-core-framework.js');
|
const Framework = require('./framework/node-core-framework.js');
|
||||||
const schedule = require('./api/middleware/schedule/index.js');
|
const schedule = require('./api/middleware/schedule/index.js');
|
||||||
|
const redis = require('./api/middleware/redis_proxy.js');
|
||||||
|
|
||||||
// 启动应用
|
// 启动应用
|
||||||
async function startApp() {
|
async function startApp() {
|
||||||
@@ -18,6 +18,12 @@ async function startApp() {
|
|||||||
// 创建框架实例
|
// 创建框架实例
|
||||||
const framework = await Framework.init(frameworkConfig);
|
const framework = await Framework.init(frameworkConfig);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 启动服务器
|
// 启动服务器
|
||||||
const port = frameworkConfig.port.node;
|
const port = frameworkConfig.port.node;
|
||||||
|
|
||||||
@@ -38,6 +44,7 @@ async function startApp() {
|
|||||||
// 启动调度系统
|
// 启动调度系统
|
||||||
await schedule.init();
|
await schedule.init();
|
||||||
|
|
||||||
|
|
||||||
// 优雅关闭处理
|
// 优雅关闭处理
|
||||||
process.on('SIGINT', async () => {
|
process.on('SIGINT', async () => {
|
||||||
console.log('\n🛑 正在关闭应用...');
|
console.log('\n🛑 正在关闭应用...');
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user