I have two model in my node/express app :
I want to use passport to authenticated them :
I correctly implemented PassportJS for the User model but now I try to do the same for Manager model.
exports.postlogin = function(req, res, next) {
passport.authenticate('user', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
req.session.messages = [info.message];
return res.redirect('/login')
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
};
exports.postlogin = function(req, res, next) {
passport.authenticate('manager', function(err, manager, info) {
if (err) { return next(err) }
if (!manager) {
req.session.messages = [info.message];
return res.redirect('/manager_signup')
}
req.logIn(manager, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
};
The two strategies :
passport.use('user', new LocalStrategy(function(username, password, done) {
UserModel.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
user.comparePassword(password, function(err, isMatch) {
if (err) return done(err);
if(isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
passport.use('manager', new LocalStrategy({usernameField: 'manager_signin_email', passwordField: 'manager_signin_password'},function(manager_signin_email, manager_signin_password, done) {
ManagerModel.findOne({ email: manager_signin_email }, function(err, manager) {
if (err) { return done(err); }
if (!manager) { return done(null, false, { message: 'Unknown manager ' + manager_signin_email }); }
manager.comparePassword(manager_signin_password, function(err, isMatch) {
if (err) return done(err);
if(isMatch) {
console.log('Manager login OK : ' + manager_signin_email);
return done(null, manager);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
The problem is for Serialize/Deserialize. For User I have this :
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
UserModel.findById(id, function (err, user) {
done(err, user);
});
});
But I don't know how to do for Manager model.
I think there is an open issue for what you want (https://github.com/jaredhanson/passport/issues/148) .
Alternatively you could change you serialize method to include information if it's user or manager not only user id and when deserializing read that info and load user/manager from proper model.
You could maybe do something like this when serializing:
if (isUser(user)) {
// serialize user
done(null, "user_"+user.id );
} else if (isManager(user)) {
// serialize manager
done(null, "manager_"+user.id );
}
And then check the prefix when deserializing.
In case anyone is still stumbling upon this. You can check the type of the object you are serializing. Note all there of by objects are generalized in to a PrincipleInfo object.
function PrincipleInfo(principleId, principleType, details) {
this.principleId = principleId;
this.principleType = principleType;
this.details = details;
}
passport.serializeUser(function (userObjectThing, done) {
//userObjectThing could be a User or a Sponsor
var principleType = "user";
var userPrototype = Object.getPrototypeOf(userObjectThing);
if (userPrototype === User.prototype) {
principleType = "user";
} else if (userPrototype === Sponsor.prototype) {
principleType = "sponsor";
} else if (userPrototype === Admin.prototype) {
principleType = "admin";
}
var principleInfo = new PrincipleInfo(userObjectThing.id, principleType, '');
done(null,principleInfo);
});
passport.deserializeUser(function (principleInfo, done) {
if (principleInfo.principleType == 'user') {
User.findOne({
_id: principleInfo.principleId
}, '-salt -hashedPassword', function (err, user) { // don't ever give out the password or salt
done(err, user);
});
} else if (principleInfo.principleType == 'sponsor') {
Sponsor.findOne({
_id: principleInfo.principleId
}, '-salt -hashedPassword', function (err, user) { // don't ever give out the password or salt
done(err, user);
});
} else if (principleInfo.principleType == 'admin') {
Admin.findOne({
_id: principleInfo.principleId
}, '-salt -hashedPassword', function (err, user) { // don't ever give out the password or salt
done(err, user);
});
}
});