سؤال

I got a problem with the Passport.js module and Express.js.

This is my code and I just want to use a hardcoded login for the first try.

I always get the message:

I searched a lot and found some posts in stackoverflow but I didnt get the failure.

Error: failed to serialize user into session
    at pass (c:\Development\private\aortmann\bootstrap_blog\node_modules\passport\lib\passport\index.js:275:19)

My code looks like this.

'use strict';

var express = require('express');
var path = require('path');
var fs = require('fs');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var nodemailer = require('nodemailer');

var app = express();

module.exports = function setupBlog(mailTransport, database){
var config = JSON.parse(fs.readFileSync('./blog.config'));

app.set('view options', {layout: false});

app.use(express.static(path.join(__dirname, '../', 'resources', 'html')));


app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'secret' }));
app.use(passport.initialize());
app.use(passport.session());


app.get('/blog/:blogTitle', function(req, res) {
  var blogTitle = req.params.blogTitle;
  if(blogTitle === 'newest'){
    database.getLatestBlogPost(function(post) {
      res.send(post);
    });
  } else {
    database.getBlogPostByTitle(blogTitle, function(blogPost) {
      res.send(blogPost);
    });
  }
});

passport.use(new LocalStrategy(function(username, password, done) {
  // database.login(username, password, done);
  if (username === 'admin' && password === 'admin') {
    console.log('in');
    done(null, { username: username });
  } else {
    done(null, false);
  }
}));

app.post('/login', passport.authenticate('local', {
  successRedirect: '/accessed',
  failureRedirect: '/access'
}));





app.listen(8080);
console.log('Blog is running on port 8080');

}();

Thanks.

هل كانت مفيدة؟

المحلول

It looks like you didn't implement passport.serializeUser and passport.deserializeUser. Try adding this:

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

نصائح أخرى

If you decide not to use sessions, you could set the session to false

app.post('/login', passport.authenticate('local', {
  successRedirect: '/accessed',
  failureRedirect: '/access',
  session: false
}));

Sounds like you missed a part of the passportjs setup, specifically these two methods:

passport.serializeUser(function(user, done) {
    done(null, user._id);
    // if you use Model.id as your idAttribute maybe you'd want
    // done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

I added the bit about ._id vs. .id but this snippet is from the Configure Section of docs, give that another read and good luck :)

Here an working but still lazy way to use sessions and still "serialisize" the values.

var user_cache = {};

passport.serializeUser(function(user, next) {
  let id = user._id;
  user_cache[id] = user;
  next(null, id);
});

passport.deserializeUser(function(id, next) {
  next(null, user_cache[id]);
});

in case or weird errors just ask yourself: "Do I rlly set '_id' in my user object?" - in most cases you dont. So use a proper attribute as key.

Make sure you have used async and await when getting user data.

passport.serializeUser((user, done) => {
   done(null, user.id);
});

passport.deserializeUser(async (id, done) => {
  const USER = await User.findById(id);
  done(null, USER);
});

passport.use(
  new GoogleStrategy(
    {
      // options for google strategy
      clientID: keys.google.clientID,
      clientSecret: keys.google.clientSecret,
      callbackURL: "/auth/google/redirect",
    },
    async (accessToken, refreshToken, profile, done) => {
      //   passport callback function

      //   check if user already exist in our db
      const oldUser = await User.findOne({ googleId: profile.id });
      if (oldUser) {
        return done(null, oldUser);
      } else {
        const newUser = await new User({
          username: profile.displayName,
          googleId: profile.id,
        }).save();
        return done(null, newUser);
      }
    }
  )
);

use this code into your server.js file where u can make a get or post request.

  app.get('/auth/facebook/callback',passport.authenticate('facebook',{
    successRedirect:'/profile',
    failureRdirect:'/',
    session: false
}))

Using Promise with serializeUser & deserializeUser:

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser((id, done) => {
  // console.log(`id: ${id}`);
  User.findById(id)
    .then((user) => {
      done(null, user);
    })
    .catch((error) => {
      console.log(`Error: ${error}`);
    });
});

Please see my github repo for a full code example how to solve this issue.

You missed this code:

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

For details, check the session part in http://www.passportjs.org/docs/configure/

Another prevalent reason for this as I discovered today is that if you are using the standard packages such as passport,passport-local,passport-local-mongoose and express-session and u are already in a session that is you were logging in and then you terminate the server and restart again, you will be in the same session while logging in where the browser keeps loading with no response and you get this error of "failed to serialize user into the session".

in passport.use('local-login'...)/ or /('local-singup'...)

if err you have to return "false" err {return done(null, req.flash('megsign', 'Username already exists #!#'));} true {return done(null, false, req.flash('megsign', 'Username already exists #!#'));}

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top