req.user недоступен в стратегии Google Passport

У меня есть экспресс-приложение, которое управляет аутентификацией через Passport, изначально с локальной стратегией. К этому я только что добавил Google вход / создание учетной записи, и почти все работает в соответствии с документами.

У меня проблема в том, что пользователь может создать учетную запись с помощью стратегии Google, но я не могу получить ее, чтобы аутентифицированный пользователь (с помощью локальной стратегии) ​​мог просто добавить дополнительные данные Google в свою учетную запись, чтобы они могли использовать либо локальную или стратегия Google.

В "index.js", где я определяю свои маршруты, я определяю const passportGoogle = require('../handlers/google'); в котором есть детали моей стратегии Google.

Дальше вниз в index.js У меня есть мой authenticate а также authorise маршруты:

/* GOOGLE ROUTES FOR AUTHENTICATION*/

router.get('/google',
    passportGoogle.authenticate('google', 
    { scope: ['profile', 'email'] }));

router.get('/google/callback', 
    passportGoogle.authenticate('google', 
    {
        failureRedirect: '/',
        failureFlash: 'Failed Login!',
        successRedirect: '/account',
        successFlash: 'You are logged in!'

    }
));

/* GOOGLE ROUTES FOR AUTHORISATION - IE A USER IS ALREADY LOGGED IN AND WANTS TO CONNECT THEIR GOOGLE ACCOUNT*/

// send to google to do the authentication
router.get('/connect/google', 
    passportGoogle.authorize('google', 
    { scope : ['profile', 'email'] }
));

// the callback after google has authorized the user
router.get('/connect/google/callback',
    passportGoogle.authorize('google', {
        successRedirect : '/profile',
        failureRedirect : '/'
    })
);

Как указано выше, моя стратегия Google определяется в google.js:

var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var User = require('../models/User');
passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENTID,
    clientSecret: process.env.GOOGLE_CLIENTSECRET,
    callbackURL: "http://127.0.0.1:7777/google/callback"
  },
  // google will send back the token and profile
function(req, token, refreshToken, profile, done) {
// console.log('here is res.locals.user'+ res.locals.user);
        console.log('here is req.user'+ req.user);
    // asynchronous
    process.nextTick(function() {

        // check if the user is already logged in
        if (!req.user) {
            console.log('THERE IS NO REQ.USR');
            // find the user in the database based on their facebook id
            User.findOne({ 'google.id': profile.id }, function(err, user) {

                // if there is an error, stop everything and return that
                // ie an error connecting to the database
                if (err)
                    return done(err);

                // if the user is found, then log them in
                if (user) {
                    return done(null, user); // user found, return that user
                } else {
                    // if there is no user found with that google id, create them
                    var newUser            = new User();

                    // set all of the facebook information in our user model
                    newUser.google.id = profile.id;
                    newUser.google.token = token;
                    newUser.name = profile.displayName;
                    newUser.email = profile.emails[0].value;

                    // save our user to the database
                    newUser.save(function(err) {
                        if (err)
                            throw err;

                        // if successful, return the new user
                        return done(null, newUser);
                    });
                }

            });

        } else {
            const user = User.findOneAndUpdate(
                { _id: req.user._id },
                { $set: {"user.google.id":profile.id, 
                        "user.google.token":accessToken, 
                        "user.google.name":profile.displayName, 
                        "user.google.email":profile.emails[0].value
                    }
                },   
                { new: true, runValidators: true, context: 'query' }
            )
            .exec();
            return done(null, user);
            req.flash('success', 'Google details have been added to your account'); 
            res.redirect(`back`); 
        }
    });
}));

module.exports = passport;

Однако, когда пользователь вошел в систему и перешел по ссылке на /connect/google всегда создается новый пользователь, а не обновляются его данные. Моя регистрация показывает, что if (!req.user) условие в Google stratgy всегда срабатывает, но я не уверен, почему это так, поскольку пользователь определенно вошел в систему.

Любая помощь высоко ценится!

1 ответ

Решение

Для того, чтобы получить доступ к требованию в вашем обратном вызове, вам нужно passReqToCallback: true Отметьте в вашем объекте конфигурации GoogleStrategy:

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENTID,
    clientSecret: process.env.GOOGLE_CLIENTSECRET,
    callbackURL: "http://127.0.0.1:7777/google/callback",
    passReqToCallback: true
  },
  // google will send back the token and profile
function(req, token, refreshToken, profile, done) {
// console.log('here is res.locals.user'+ res.locals.user);
        console.log('here is req.user'+ req.user);
....
})

Если этот флаг опущен, ожидаемая форма обратного вызова

function(accessToken, refreshToken, profile, done){...}

Итак, ваш код ищет user свойство на accessToken, которое Google отправляет обратно, что всегда должно давать сбой. Я также говорю об этом, потому что, если я прав, другие части вашей функции также должны плохо себя вести. (Подобно User.findOne({'google.id': profile.id}) должен всегда терпеть неудачу, потому что функция вызывается с done в качестве четвертого аргумента, а не profile.)

Другие вопросы по тегам