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 для каждого из двух вариантов.