SetTimeout 在 Mongoose 模式 post 中间件中不起作用

SetTimeout is not working in Mongoose schema post middleware

我正在尝试在生成 forgetpassword_token 24 小时后将 mongodb 文档中的 forgetpassword_token 更新为 null。所以我正在使用 Mongoose 模式中间件和 setTimeout,但是 setTimeout 不工作。

我已经尝试实现异步等待,但根据我的结果也无法正常工作。

CompanySchema.post('updateOne',true, function(doc,next){
    next();
       setTimeout(this.update({},{ $set: { forgetpassword_token: null } }).then(result=>{
           console.log(result);
                   }),10000000000);
       });

这里的主要问题是这个实现是有缺陷的,因为如果你的节点应用程序在 24 小时 window 期间重新启动,你的超时将 消失 (是内存中的对象,未持久化)并且令牌将保持活动状态,使您面临安全风险。

手动令牌验证

一个非常常见的解决方案是将 token_expiration_date 与令牌一起保存,在相关密码重置请求期间进行日期比较。如果 token_expiration_date 过期,请求 return 出错,服务器必须删除数据库上的令牌。

您也可以相反:将 token_creation_datemax-token-ttl 存储在您的应用程序代码中(例如 24 小时)。在任何情况下,您都会在请求时进行日期比较。

@NikKyriakides 建议(参见评论)此方法的更复杂版本:如果令牌有效调用单个方法(无手动日期比较),则创建单个 JWT token that contains itself the expiration date. When the user request the reset password page you need only to verify

Mongo 过期选项

一个更优雅和有效的解决方案是为您的 forgetpassword_token 创建一个不同的 mongoose 模式,并使用本机 mongo/mongoose expire option 在创建后的固定时间后自动删除文档.

const secondsInADay = 60 * 60 * 24;

const tokenSchema = mongoose.Schema({
    value: String
}, {timestamps: true});

tokenSchema.index({createdAt: 1},{expireAfterSeconds: secondsInADay});
const Token = mongoose.model('Token', tokenSchema);

然后将对此架构的引用添加到您现有的 CompanySchema 中:

forgetpassword_token: {type: mongoose.Schema.Types.ObjectId, ref: 'Token'}

this topic, so please also check them alongside with the related mongoose documentation 上存在很多问题。

作业调度程序

另一种方法是使用像 agenda 这样的作业调度程序来每小时检查过期的令牌并删除它们。是的,您可以将基于 setTimeout 的检查编写为应用程序的模块,但如果合适的工具已经存在,为什么不使用它呢?另请查看下面的@NikKyriakides 评论,了解此解决方案的潜在缺点。