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
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)
})
}
));
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);
} );
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
//*********************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 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!