Authentication is a mechanism of verifying users coming to particular system so that they can only make use of resources for which they have been provided permission. Having a strong authentication mechanism in an important part of a system.
Thus in order to save developer from taking all the pain for developing authentication module Node.js provide us with a very robust and powerful middleware known as Passport which take care of all our authentication concerns.
Acting a middleware Passport does an excellent job by separating other modules of application from authentication module. Passport can be very easily configured with application being built on Express.
For authentication Passport have a long list of mechanism as per Passport documentation there are more then 140+ authentication mechanisms we can choose from. User can be authenticated against a local/remote database or single sign-on using OAuth providers for Facebook,Twitter etc. If you want to make use of Passport for authentication using facebook,google etc you need to install library being provided by individual social-media.
For this tutorial we are using local storage so we will start with installing Passport first
npm install passport
As we are going for local authentication against value stored in our database we need to install passport-local module:
npm install passport-local
Before moving ahead with the tutorial make sure all these are added to package.json as local dependencies :
"passport": "~0.2.0",
"passport-local": "~1.0.0"
Configuring Passport With Express
As passport only provide us with mechanism to handle authentication , thus for handling session we would require other module know as express-session . To install module type :
npm install --save express-session
To attach passport with express open app.js and add the following code :
// Configuring Passport
var passport = require('passport');
var expressSession = require('express-session');
app.use(expressSession({secret: 'mySecretKey'}));
app.use(passport.initialize());
app.use(passport.session());
Serializing and Deserializing User Instances
While making use of passport we also need to serialize and deserialize user instance from a session store in order to support login sessions, so that every subsequent request will not contain the user credentials. Passport provide us with two inbuilt methods for the same serializeUser and deserializeUser :
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Using Passport for Login and SignUp :
Now we will be making use of passport strategies for handling login and signup , each of these will make use of Local Authentication Strategy of passport making use of
passport.use()
Making use of passport login would look something like this :
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'username' : username },
function(err, user) {
// In case of any error, return using the done method
if (err)
return done(err);
// Username does not exist, log error & redirect back
if (!user){
console.log('User Not Found with username '+username);
return done(null, false,
req.flash('message', 'User Not found.'));
}
// User exists but wrong password, log the error
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false,
req.flash('message', 'Invalid Password'));
}
// User and password both match, return user from
// done method which will be treated like success
return done(null, user);
}
);
}));
The first parameter to passport.use() is the name of the strategy . The second parameter is the type of strategy that you want to create i.e LocalStrategy.
Using passport for registration would look something like this :
passport.use('signup', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({'username':username},function(err, user) {
// In case of any error return
if (err){
console.log('Error in SignUp: '+err);
return done(err);
}
// already exists
if (user) {
console.log('User already exists');
return done(null, false,
req.flash('message','User Already Exists'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.username = username;
newUser.password = createHash(password);
newUser.email = req.param('email');
newUser.firstName = req.param('firstName');
newUser.lastName = req.param('lastName');
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute
// the method in the next tick of the event loop
process.nextTick(findOrCreateUser);
});
);
Once login and registration logic is done we will make changes in our routes to make use of passport :
module.exports = function(passport){
/* GET login page. */
router.get('/', function(req, res) {
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
});
/* Handle Login POST */
router.post('/login', passport.authenticate('login', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash : true
}));
/* GET Registration Page */
router.get('/signup', function(req, res){
res.render('register',{message: req.flash('message')});
});
/* Handle Registration POST */
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/home',
failureRedirect: '/signup',
failureFlash : true
}));
return router;
}
The most important thing to note over here is passport.authenticate() to delegate the authentication to login and signup strategies .
Beside this passport also provide you mechanism for protecting routes i.e if a particular user is restricted to visit home page without authentication , he will be redirected to some other page :
/* GET Home Page */
router.get('/home', isAuthenticated, function(req, res){
res.render('home', { user: req.user });
});
// As with any middleware it is quintessential to call next()
// if the user is authenticated
var isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
0 Comment(s)