passport local type error

2019-06-01 05:26发布

问题:

I'm trying to use passport-local for authentication in my Sails project. In my controller:

passport.authenticate('local', function(err, user, info) {

  if ((err) || (!user)) { res.json({message: 'Unable to authenticate'}); return; }

  req.login(user, function(err) {

    if (err) { res.json({message: 'Unable to login'}); console.log(err); return; }
    res.json({message: 'logging in'});

  });

})(req, res);

In a config file:

passport.use(new LocalStrategy(function(username, password, done) {

  User.findOneByUsername(username).done(function(err, user) {

    if (err) { return done(null, err); }
    if (!user) { return done(null, false, { message: 'Incorrect User' }); }

    bcrypt.compare(password, user.password, function(err, res) {

      if (err) { return done(null, err); }
      if (!res) { return done(null, false, { message: 'Invalid Password'}); }

      return done(null, user);

    });
  });
}));

The response is 'Unable to Login'. The console output is: [TypeError: Cannot read property 'id' of undefined]

I'm new to passport, and I'm not entirely sure where it's failing, since it seems to actually be finding the user, and comparing the passwords successfully in the config file (some console logs seem to indicate as much). But the req.login callback has an error, which means login is failing even though authentication is succeeding. I'm lost as to why I'm getting this error.

回答1:

Turns out I was trying to outsmart a tutorial. The tutorial is this one:

http://jethrokuan.github.io/2013/12/19/Using-Passport-With-Sails-JS.html

It recommends using this passport setup:

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

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

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findByUsername(username).done(function(err, user) {
      if (err) { return done(null, err); }
      if (!user || user.length < 1) { return done(null, false, { message: 'Incorrect User'}); }
      bcrypt.compare(password, user[0].password, function(err, res) {
        if (!res) return done(null, false, { message: 'Invalid Password'});
        return done(null, user);
      });
    });
  })
);

But as you can see from my code above, I changed that to findOneByUsername, thinking that the tutorial had made some mistake. Turns out it hadn't. The 'id' which the error message refers to is the second line of the code I've just posted, where user[0] is undefined when user is an object, as oppose to an array of objects.

However, in the comments, the author claims he's made some mistakes, including the possible redundancy of authenticating then logging in, which is contradictory in the passport docs. In one place the docs recommend it, in another they say it's completely unnecessary. And why we'd want to pull out a bunch of users from the datastore using one id when there should only be one seems silly to me.

Oh well.