Я использую 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
пользователя и поле токена, сгенерированное из вышеуказанного набора, вместе с датой истечения срока действия - Отправьте электронное письмо новому пользователю с URL-адресом, содержащим его мангуста
_id
и его токен (/u/${id}/is-valid/${token}
). - При посещении этого URL,
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 });
}
Если это невозможно, какие другие подходы я могу использовать для достижения этой цели? Это должна быть довольно распространенная стратегия регистрации.
*Это что-то вроде хака, поскольку passport.js предполагает регистрацию с именем пользователя и паролем (не по электронной почте)