How to use passport.js for different kinds user authentication? - node.js

I'm trying to have 2 different users by having 2 collections in my MongoDB database. So, I wants to have
separate authentication. I had done this.
passport.use('patient', new LocalStrategy({usernameField:'email'},
function(username, password, done){
patient.findOne({email: username}).then(user => {
if(!user){
console.log("no patient exists");
return done(null, false);
}
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
console.log("incorrect patient password");
return done(null, false);
}
});
})
}));
And I had serialized and deserialized my passport.
passport.serializeUser(function(user, done) {
console.log(user._id );
console.log(user.speciality);
done(null, {id: user._id, isPatient: user.speciality===undefined});});
passport.deserializeUser(function(user, done) {
// User.findById(id, function(err, user) {
// done(err, user);
// });
if(user.isPatient){
patient.findById(user.id, function(err, user){
done(err, user);
});
}else{
doctor.findById(user.id, function(err, user){
done(err, user);
})
}});
But when I'm trying to login my website is only loading but ain't showing any error or redirecting.
Please help me.

Related

Can I deserialize the different users like student and admin in passport.js?

In passport js authentication when the deserialize the user I have the following doubt?
Can I use different Login tables to fetch the user ?(depends on they are admin or student like that)
But I was try to implement it by using if statement that was won't work it which mean cannot fetch from db. What I am doing that any help !
Using LocalStrategy u can use it. Here you have to make two different calls to check.
Sample:
passport.use(new LocalStrategy(
function(username, password, done) {
async.parallel([
function(cb){
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return cb(null, user);
});
},
function(cb){
Admin.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return cb(null, user);
});
}
], ([res1, res2]) => {
// on result
done(null, res1)
// OR
done(null, res1)
})
}
));

Serialize different types of users in PassportJS

I have two local strategies for two different types of users: Students and Teachers. I am having trouble trying to login because my serialization is not working properly.
I have two models, Student and Teacher. Both have their separate collections, student and teacher with similar schema. Both have similar functions:
module.exports.getStudentByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.getStudentById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
My two local strategies are:
passport.use('student-local', new LocalStrategy(
function(username, password, done) {
Student.getStudentByUsername(username, function(err, student){
if(err) throw err;
if(!student){
return done(null, false, {message: 'Unknown Student'});
}
Student.comparePassword(password, student.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, student);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
passport.use('teacher-local', new LocalStrategy(
function(username, password, done) {
Teacher.getTeacherByUsername(username, function(err, teacher){
if(err) throw err;
if(!teacher){
return done(null, false, {message: 'Unknown Teacher'});
}
Teacher.comparePassword(password, teacher.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, teacher);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
My two logins are:
router.post('/loginStudent',
passport.authenticate('student-local', {successRedirect:'/users/student', failureRedirect:'/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
router.post('/loginTeacher',
passport.authenticate('teacher-local', {successRedirect:'/users/teacher', failureRedirect:'/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
My serialization and deserialization are:
passport.serializeUser(function(user, done) {
if(Student.findOne({username: user.username}).length != 0) {
done(null, user.id);
} else if(Teacher.findOne({username: user.username}).length != 0) {
done(null, user.id);
}
});
passport.deserializeUser(function(id, done) {
if(Student.getStudentById(id)){
Student.getTeacherById(id, function(err, user) {
done(err, user);
});
} else {
Teacher.getTeacherById(id, function(err, user) {
done(err, user);
});
}
});
I know my serialization is wrong and that is why I am not being able to get this to work. When I tried with only one type of user and with the simpler serialization I found in the passport documents, my login was working fine.I am new with node and passport so any help would be highly appreciated.
I believe your serialization doesn't work, because the query for finding the teacher / student is actually async and you are treating it as sync.
passport.serializeUser(function(user, done) {
Student.findOne( { username: user.username }, function( err, student ) {
if ( student ) {
// user is student
done( null, user.id );
} else {
Teacher.findOne( { username: user.username }, function( err, teacher ) {
if ( teacher ) {
// user is teacher
done( null, user.id );
}
} );
}
} )
} );
This should work, although I'm not sure why you are doing to lookup for the type of user. You can just do :
passport.serializeUser(function(user, done) {
done(null, user.id);
} );

How to disable serializeuser and deserializeuser for specific strategy

I have code like this:
passport.serializeUser(function (user, done) {
console.log('serializing user ' +user._id);
return done(null, user._id);
});
passport.deserializeUser(function (id, done) {
console.log(id);
Users.findById(id, function (err, user) {
console.log('deserialize user ' +id);
done(err, user);
});
});
passport.use('login', new LocalStrategy({
passReqToCallback: true
},
function (req, username, password, done) {
Users.findOne({username: username}, function (err, user) {
if(err){
return done(err);
}
if(!user){
console.log('User Not Found with username '+username);
return done(null, false);
}
if(!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false); // redirect back to login page
}
return done(null, user);
}
);
})
);
passport.use('signup', new LocalStrategy({
passReqToCallback: true
},
function (req, username, password, done) {
Users.findOne({username: username}, function (err, user) {
if(err){
return done(err);
}
if(user){
console.log('User already exists with username: '+username);
return done('User already exists', false);
}
else{
var newUser = new Users();
newUser.username = username;
newUser.password = createHash(password);
newUser.save(function (err) {
if(err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log(newUser.username +' Registered Successfully');
return done(null, newUser);
});
}
});
})
);
var isValidPassword = function (user, password){
return bCrypt.compareSync(password, user.password);
};
var createHash = function (password){
return bCrypt.hashSync(password,bCrypt.genSaltSync(10), null);
};
The problem is, when client sign-up new user and registered successfully. client will be automatically authenticated.
How to make client is still not authenticated until he/she is log-in??
So the flow I want is:
1. client register new ID
2. Client still not authenticated until he/she is login
3. client login
4. Client is authenticated now

I was able to authenticate an existing user but I couldn't create new user account? Here is my Code

//*********************This was to authenticate user*********************
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
UserDetails.findOne({
'username': username,
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false);
}
if (user.password != password) {
return done(null, false);
}
return done(null, user);
});
});
}));
//*********************This was to create new user*********************
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
UserDetails.findOne({
'username': username,
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
var newUser = new UserDetails({"username":newUsername, "password":newPassword});
newUser.save(function (err, newUser) {
if (err)
{
return console.error(err);
}
console.log("Document Saved!");
});
return done(null, true);
}
});
});
}));
I have a login.jade file and signup.jade. So, when I want to sign in a user - if the user is in the database, it will authenticate the user successfully. But if the user does not exist it will insert a new user the database.
So my question is what should I change in code so that the a new user would be able to create account using the signup page and and an existing user would be able use login?
Thanks

How to serialize/deserialize multiple local strategie

How can I serialize/deserialize multiple local strategies:
I have already tried this Use multiple local strategies in PassportJS but not success.
This is my code :
passport.use('user', new LocalStrategy( function(username, password, done) {
UserSchema.findOne({ username: username }, function(err, user) {
// ...
return done(null, user);
});
}));
passport.use('admin', new LocalStrategy( function(username, password, done) {
adminSchema.findOne({ username: username }, function(err, user) {
// ...
return done(null, user);
});
}));
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
adminSchema.findById(id, function(err, user){
if(err) done(err);
if(user){
done(null, user);
} else {
user.findById(id, function(err, user){
if(err) done(err);
done(null, user);
})
}
});
I was working on the same problem. I took your code and changed a few things and it worked for me! Make sure to log out of one account before trying another or just use an incognito tab.
Here is the updated code I used:
passport.use('user', new LocalStrategy( function(username, password, done) {
UserSchema.findOne({ username: username }, function(err, user) {
// ...
return done(null, user);
});
}));
passport.use('admin', new LocalStrategy( function(username, password, done) {
adminSchema.findOne({ username: username }, function(err, user) {
// ...
return done(null, user);
});
}));
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
adminSchema.findById(id, function(err, user){
if(err) done(err);
if(user){
done(null, user);
} else {
UserSchema.findById(id, function(err, user){
if(err) done(err);
done(null, user);
})
}
});
My schema names are different so I changed them to match yours. One issue you might have is using UserSchema instead of userSchema. Try that next if it doesn't work.
Hope this helps!

Resources