Аутентифицировать нового пользователя с помощью passport.js только после подтверждения электронной почты - PullRequest
0 голосов
/ 29 сентября 2019

Я использую 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 предполагает регистрацию с именем пользователя и паролем (не по электронной почте)

...