Req.session.passport пуст, deserializeUser не вызывается - ExpressJS, паспорт

У меня возникают проблемы с использованием сеансов в Passport/ExpressJS.

Когда я запишу req.session, я вижу, что этот паспорт {}:

{ cookie: 
 { path: '/',
  _expires: Mon Sep 29 2014 19:37:16 GMT-0300 (BRT),
  originalMaxAge: 3594522,
  httpOnly: true,
  secure: true },
passport: {} }

Кроме того, я аутентифицирую с помощью Facebook, а passport.deserializeUser не вызывается. Это мой код:

    passport.use(new FacebookStrategy({

    // pull in our app id and secret from our auth.js file
    clientID        : configAuth.facebookAuth.clientID,
    clientSecret    : configAuth.facebookAuth.clientSecret,
    callbackURL     : configAuth.facebookAuth.callbackURL

},

// facebook will send back the token and profile
function(token, refreshToken, profile, done) {

    // asynchronous
    process.nextTick(function() {

        console.log("profile " + profile.id);
        console.log("profile.name "+profile.name.givenName)

        // find the user in the database based on their facebook id
        User.findOne({ 'facebook.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) {
                //returning undefined
                //console.log(user.name + " " + user.email);
                return done(null, user); // user found, return that user
            } else {
                // if there is no user found with that facebook id, create them
                var newUser = new User();

                // set all of the facebook information in our user model
                newUser.facebook.id    = profile.id; // set the users facebook id
                newUser.facebook.token = token; // we will save the token that facebook provides to the user
                newUser.facebook.name  = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
                newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first

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

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

        });
    });

}));

// used to serialize the user for the session
passport.serializeUser(function(user, done) {
    console.log("serialize");
    done(null, user.id);
});

// used to deserialize the user
passport.deserializeUser(function(id, done) {
    console.log("deserialize");
    User.findById(id, function(err, user) {
        console.log(user);
        done(err, user);
    });
});

Я попытался перевести оба метода в начало, но это не имело никакого значения. passport.serializeUser называется просто отлично.

Здесь я инициализирую passport:

app.use (cookieParser());
app.use(session({ secret: 'appsecret', saveUninitialized: true, cookie: { secure: true, maxAge: new Date(Date.now() + 3600000) }, key:'connect.sid' }));

app.use(passport.initialize());
app.use(passport.session());

И это мой route:

// =====================================
// FACEBOOK ROUTES =====================
// =====================================
// route for facebook authentication and login

app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));

// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
    passport.authenticate('facebook', {
        successRedirect : '/home',
        failureRedirect : '/login'
    }));

Может кто-нибудь мне помочь?

Спасибо!

Ответ 1

Фон

Для меня проблема с deserializeUser, которая не называется и пустой объект паспорта, была проблемой междоменного доступа. Когда я отправлял запрос ajax с localhost: 4200 на localhost: 1000 куки файлов и сеансов не работали для моего клиента Ember.js. Однако расширение Postman получило правильный ответ. Также объект паспорта правильно заполнен данными. User.deserializeUser правильно вызывается.

Решение

Чтобы решить эту проблему, мне пришлось установить правильные серверные и клиентские HTTP-заголовки. Серверная (node.js + express + паспорт):

# The important part. Must go AFTER the express session is initialized
app.use passport.initialize()
app.use passport.session()

# Enable CORS
# X-Requested-With, X-AUTHENTICATION, X-IP
# /questions/26173/missing-options-request-using-ember-data/191322#191322
app.use (req, res, next) ->
  res.header 'Access-Control-Allow-Origin', 'http://localhost:4200'
  res.header 'Access-Control-Allow-Headers', 'Origin, X-Requested-With, X-AUTHENTICATION, X-IP, Content-Type, Accept'
  res.header 'Access-Control-Allow-Credentials', true
  res.header 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'
  next()

app.use '/api/v1', router

на стороне клиента:

Если вы используете jQuery, добавьте это в опции $.ajax:

xhrFields: { withCredentials:true }

Затем все работает так, как ожидалось:

DESERIALIZE USER
{ id: '547fabf22a098ade53e6e48e',
  name: 'test',
  firstName: 'test',
  email: '[email protected]' }
LOGIN SUCCESS SESSION
{ cookie: 
   { path: '/',
     _expires: Thu Dec 04 2014 20:26:52 GMT+0100 (CET),
     originalMaxAge: 3597205,
     httpOnly: false },
  passport: 
   { user: 
      { id: '547fabf22a098ade53e6e48e',
        name: 'test',
        firstName: 'test',
        email: '[email protected]' } } }

Эти ответы помогли мне: о Ember.js, jQuery.ajax.

Ответ 2

Для меня основной причиной было значение безопасности cookie в экспресс-сессии.

app.use(require('express-session')({
    secret: 'crackalackin',
    resave: true,
    saveUninitialized: true,
    cookie : { secure : false, maxAge : (4 * 60 * 60 * 1000) }, // 4 hours
}));

На моей локальной машине я не работал по HTTP, поэтому, когда cookie.secure является истинным, сеанс и пользовательский объект были пустыми. Когда в режиме dev и secure было false, он работал правильно.

Ответ 3

Мое решение должно было быть последовательным в отношении ссылок на разные страницы моего сайта.

Префикс URL ссылки с 'www.' при аутентификации, где нет "www". начнет новый сеанс при ссылке на эту префиксную страницу. Вы можете проверить это с помощью средства просмотра файлов cookie, посмотрите, есть ли несколько файлов cookie для каждого из двух вариантов.