我将passport.js与mongoose(mongoDB)(和passport-local-mongoose)结合使用,以在节点/快速后端中创建和认证用户帐户。
我当前使用的策略是:
username
输入type="email" name="username"
和password
输入name='password'
(还有其他内容) * let newUser = new Profile({username: req.body.username, ...})
crypto.randomBytes(...)
Profile.register(newUser, password)
和passport.authenticate
用户和从上面的集合生成的集合令牌字段以及到期日期_id
和令牌(/u/${id}/is-valid/${token}
)。 Profile.findOne({_id: req.params.id})
并检查令牌是否匹配,并且尚未过期这种方法的问题在于,在同时调用Profile.register
和passport.authenticate
时,会在用户验证电子邮件之前创建一个预先认证的帐户。
如何分离这两种方法,以便只有在验证用户的电子邮件地址后才能对用户进行身份验证?
以下是我如何称呼Profile.register
和passport.authenticate
(作为async.waterfall([])
的一部分:
Profile.register(user, pw)
.then(response => {
passport.authenticate("local")(req, res, function(err) {
if (err) return callback(err);
user.resetEmailToken = token;
user.resetEmailExpires = Date.now() + 8.64e+7; // 1 day
user.save(function(err) {
callback(err, token, user);
});
});
})
.catch(err => {
return callback(err);
});
我想像上面一样Profile.register
,但是只有在检查了令牌后才passport.authenticate
。
这是我检查令牌的方式(通过电子邮件中包含的访问链接-/u/${id}/is-valid/${token}
):
async verifyEmail(req, res, next){
let user = await Profile.findOne({ '_id': req.params.id })
if(!user) return res.redirect("back");
if (user.resetEmailToken != req.params.token){
req.flash("error", "Tokens don't match");
return res.redirect("back");
}
if(user.resetEmailExpires < Date.now()){
console.log("This date has expired", moment(user.resetEmailExpires).calendar());
return res.redirect(`/signup?token-expired=${user.email}`);
}
user.isVerified = true;
// Here is where I want to passport.authenticate() and redirect to their new profile
user.save();
return res.render('login', { user: user });
}
如果这不可能,那么我可以采取什么其他方法来实现这一目标?它必须是一种相当普遍的注册策略。
* 这有点像hacker.js假定使用用户名和密码(不是电子邮件)注册了