如何在AuthJs(NextAuth)中实现登录后8小时自动删除未验证用户的触发逻辑
如何在AuthJs(NextAuth)中实现登录后8小时自动删除未验证用户的触发逻辑
嘿,我来帮你梳理下实现这个需求的具体步骤,结合你用的NextAuth、Mongoose和Next.js,咱们一步步来落地:
第一步:完善用户模型(补充关键字段)
你当前的User Schema缺少两个核心字段:邮箱验证状态和登录时间。NextAuth的MongoDB Adapter其实默认会生成emailVerified字段(验证后存时间,未验证则为null),咱们把它加到Schema里,再新增lastLoginAt字段记录用户登录时间,这样才能准确计算8小时的窗口期:
import { Schema, Model, Types, Document, model, models } from 'mongoose'; export interface Users extends Document { name: string email: string emailVerified: Date | null; // 新增:标记邮箱是否验证,未验证为null lastLoginAt: Date; // 新增:记录用户最后登录的时间点 } const UserSchema = new Schema<Users>({ name: { type: String, required: true }, email: { type: String, required: true, unique: true // 建议加上,避免重复邮箱注册 }, emailVerified: { type: Date, default: null }, lastLoginAt: { type: Date, required: true } }) export default models.User || model<Users>('User', UserSchema)
第二步:在NextAuth中记录登录时间
因为你的计时是从用户登录后开始算的,所以要在signIn回调里更新用户的lastLoginAt字段,确保每次登录都刷新这个时间:
export const { auth, handlers, signIn, signOut } = NextAuth({ adapter: MongoDBAdapter(client), session: { strategy: "jwt" }, callbacks: { async session({ session, token, user }) { return { ...session, user: { ...session.user, emailVerified: user?.emailVerified, // 可选:把验证状态带到前端session里 lastLoginAt: user?.lastLoginAt }, } }, // 新增signIn回调,更新登录时间 async signIn({ user, account, profile, email, credentials }) { // 登录成功后,更新当前用户的lastLoginAt为当前时间 if (user.id) { await models.User.findByIdAndUpdate( user.id, { lastLoginAt: new Date() }, { new: true } ); } return true; // 允许登录 } }, ...authConfig, })
第三步:实现自动删除的触发逻辑
这里有两种靠谱的方案,推荐结合使用:
方案一:定时任务(核心推荐)
用node-cron包定期扫描数据库,自动删除符合条件的用户。这种方式最可靠,不管用户有没有后续操作,都会按时执行清理。
- 先安装依赖:
npm install node-cron # 或 yarn add node-cron
- 在项目中创建清理脚本,比如
scripts/cleanupUnverifiedUsers.ts:
import cron from 'node-cron'; import User from '@/models/User'; // 替换成你的User模型路径 import mongoose from 'mongoose'; import { connectDB } from '@/lib/db'; // 替换成你的数据库连接函数 // 定义清理逻辑 const cleanupUnverifiedUsers = async () => { try { await connectDB(); // 连接数据库 const eightHoursAgo = new Date(Date.now() - 8 * 60 * 60 * 1000); // 删除未验证且登录超过8小时的用户 const result = await User.deleteMany({ emailVerified: null, lastLoginAt: { $lt: eightHoursAgo } }); console.log(`成功清理 ${result.deletedCount} 个未验证超时用户`); } catch (error) { console.error('清理未验证用户出错:', error); } finally { await mongoose.connection.close(); // 关闭数据库连接 } }; // 设定定时规则:比如每小时执行一次(可根据需求调整频率) cron.schedule('0 * * * *', () => { console.log('开始执行未验证用户清理任务...'); cleanupUnverifiedUsers(); });
如果是部署在Vercel上,你可以直接用Vercel自带的Cron Jobs功能,在控制台配置定时任务,不用自己维护node-cron进程。
方案二:请求时检查(补充兜底)
除了定时任务,你可以在用户每次请求时(比如session回调里)检查当前用户是否符合删除条件,及时清理活跃的超时用户:
// 在session回调中添加检查逻辑 async session({ session, token, user }) { if (user?.emailVerified === null && user?.lastLoginAt) { const eightHoursAgo = new Date(Date.now() - 8 * 60 * 60 * 1000); // 如果用户未验证且登录超过8小时,直接删除并退出 if (new Date(user.lastLoginAt) < eightHoursAgo) { await models.User.findByIdAndDelete(user.id); await signOut({ redirect: false }); return null; // 返回空session,前端可处理跳转至登录页 } } return { ...session, user: { ...session.user, emailVerified: user?.emailVerified, lastLoginAt: user?.lastLoginAt }, } },
注意事项
- 测试时可以把时间缩短(比如1分钟),方便快速验证逻辑是否正常
- 确保数据库连接函数能在定时任务中正常工作
- 如果用Next.js App Router,定时脚本可以放在
app/api/目录下作为API路由,或者在服务器启动时执行
备注:内容来源于stack exchange,提问作者Febry Aryo
相关产品推荐
相关产品推荐

