This is part 2 in the series of developing a basic Web Application using MEAN Stack. MEAN is actually a combination of multiple language platforms to create applications. It is a shorthand wherein M stands for MongoDb, E stands for Express, A stands for Angular.js and N stands for Node.js.
In the previous part of this MEAN Stack Application, we covered the following things:
- Environment Setup for MEAN Web Development
- Routes for MEAN Stack Application
- User Registration Process
Alright so far so good, now let's start with validation and DAO part of register module.
In routes folder, where we have added method to render view for register, in the same file, we will be adding code, for what will happen when there will be a post
request.
router.post("/register", function(req,res){
var name = req.body.name;
var userName = req.body.username;
var password = req.body.password;
var email = req.body.email;
);
As we can see now, we have added post
on "/register" that is coming from UI. Now to get values from request, the below syntax is used:
req.body.<fieldname>
So as we did, we received all four values from our view and now it's up to the controller to validate the values and store them in database.
Let's first validate these values:
To validate, we have already added validator module in our code main file that is main.js, now all we need to do is to validate the data. Syntax to validate data is:
req.checkBody(<Field_Name>," Error_Message").<Validator_Function>;
So in the syntax above, Field_Name
will be the name of field that needs to be validated, Error_message
will the error message that we need to display in case validation fails, Validator_Function
is the function that will be specific to data object, for example, for name we will check with NotEmpty()
, whereas for email we will check with NotEmpty()
as well as with isEmail()
methods. Let's now write code to validate data. In the same method that is written above, we will add some validation part now. Below is the code that will validate the data.
req.checkBody("name"," Name is required ").notEmpty();
req.checkBody("email"," Email is required ").notEmpty();
req.checkBody("email"," Invalid email id").isEmail();
req.checkBody("username"," Username is required ").notEmpty();
req.checkBody("password"," Password is required ").notEmpty();
Now we have our validation code in place. Now, the question arises as to how these will work, how these error messages will be displayed to the client, who will be responsible for this and so on and so forth. So our next task is to get all the errors and direct to register view. Let's do this:
var error = req.validationErrors();
The above piece of code will collect all the errors if any in the validation part. Now our task is to use this and forward to the client. Let's write a small piece of code for this as well.
if(error){
res.render('register',{error:error});
}
So if there is any error, render the register view with errors in it. Before we restart the server and test, we need to add some piece of code in view part as well.
{{#if error}}
{{#each error}}
<div class="alert alert-danger">{{msg}}</div>
{{/each}}
{{/if}}
So this is the code that we will be adding to our register view. Traverse through each error object and display it.
Now we are good to go with the testing part of register view. Let's restart the server and see if we got all that we have expected or not. So in the example snippet below, I have added email, username, password and not name, let's submit now and see what happens.
Upon submitting this page, what we will get is:
And the same validation will work for all data fields. So we are good with the validation part of our register module. Now when validation is working fine, we have data object, so we will be happy to store the data in database and register user to our application. In the next section, we will be talking about storing data to the database.
So now when everything goes fine and there is no validation error in our page, we will like to store data in the database and register user to use our application. So what we will do is create a user object and populate this with the values we got from request and pass to dao layer for persistence.
var user = new userObject({
name:name,
email:email,
username:userName,
password:password
});
userObject.createUser(user, function(error,user){
if(error) throw error;
});
req.flash('success_message', 'Resisteted Successfully');
res.redirect('/users/login');
Here, we have createUser
method that we will write in dao layer part, next thing is, if everything goes fine and there is no error, then we will notify user with success message, which will state that registration is successful and the last thing we will do is to redirect the user to login page so that user can login, with the credentials. Let's now move to dao layer, where we will write createUser
function.
Remember when we talked about the different folders, we talked about models folder that is responsible for data interaction part with database. So we will start writing our code in user.js which is DAO layer for our application. Here, we will be creating the createUser
function.
module.exports.createUser = function(userObject,callback){
userObject.save(callback);
}
This piece of code will store our data in database. Let's test this, we need to start the server, and in browser, go to localhost:8777, since our app is listening at port number 8777.
On register page, we have filled the information and we are going to post the request. Let's see if our code works fine.
Upon post, what we get is the below screen. So our registration code is working fine and we have redirected to the sign-in page.
Great!! Isn't it, we have successfully registered user Ahmad
. Let's check in our db for the values.
So we have all the values stored that we have passed from UI. But there is one glitch, if you can at the db data, we are storing password in plain text. By doing so, we are creating a security loophole in our application. It should not happen right, one can take dump of our database and easily hack our system. What to do now..
Calm down, here crypto comes to rescue us. So it's a thumb rule that we should not and we must not store password as plain text in database. So what we will do is encrypt the password and then save to database.
First, we need to have this module with our application, let's add this:
var crypto = require('crypto');
Now we are all set to use crypto capability and functions. So what we are going to do is to encrypt the password using sha512 algorithm and persist to database. Lets write code for this:
var generateHash = function(password){
var hash = crypto.createHmac('sha512', 'Secret');
hash.update(password);
var value = hash.digest('hex');
return value;
};
The code block above will generate hash for the given data using sha512 algorithm. So we are going to use this function and encrypt our password and try to persist.
In createUser
function, we will call this generateHash
function. Let's amend the createUser
method now:
module.exports.createUser = function(userObject,callback){
var hash = generateHash(userObject.password);
userObject.password = hash.passwordHash;
userObject.save(callback);
}
And we are all set to go and test our application. Before proceeding, we are going to remove the data from database, since it was incorrect. Let's remove data and restart the server.
Then, with the same dataset, we are going to register user, So we are not repeating the same screens as above, assuming that we have inserted the same data as above. Let's check in database now:
So if you can see, now we have encrypted password in our database, and this completes the registration module.
Let's start writing code for login module.
So we will use something called passport for login module. First, we need to import passport
and passport-local
in our code so we can use the capabilities of this.
var passportObject = require("passport");
var passportLocal = require("passport-local").Strategy;
Here, we have created two ref
s, one for passport
and another for Passport-local
. Since we will be using passport local Strategy in our login module.
Passport overview from http://passportjs.org/docs
Passport is authentication middleware for Node. It is designed to serve a singular purpose: authenticate requests. When writing modules, encapsulation is a virtue, so Passport delegates all other functionality to the application. This separation of concerns keeps code clean and maintainable, and makes Passport extremely easy to integrate into an application.
In modern web applications, authentication can take a variety of forms. Traditionally, users log in by providing a username and password. With the rise of social networking, single sign-on using an OAuth provider such as Facebook or Twitter has become a popular authentication method. Services that expose an API often require token-based credentials to protect access.
Passport recognizes that each application has unique authentication requirements. Authentication mechanisms, known as strategies, are packaged as individual modules. Applications can choose which strategies to employ, without creating unnecessary dependencies.
Once we are setup with passport objects, like register, we will write post handling for login. Let's write the code for the same:
router.post('/login',
passportObject.authenticate('local',
{successRedirectUrl:"/",failureRedirectUrl:"/users/login", failureFlash :true}),
function(req, res) {
res.redirect("/");
});
So in the code above, we are using authenticate
method of passport
, which has a parameter as "local
", since we are using local database, other parameters are success
and failure
URLs and a Boolean flag as do we need to display the flash messages or not.
Now passport local will come into play and in the next section, we will be talking about fetching values from database and authenticating user.
passportObject.use(new passportLocal(
function(username, password, done) {
userObject.findByUsername(username, function(error, foundUser){
if(error) throw error;
if(!foundUser){
done(null, false, {msg : 'Auhentication failed, Invalid Username !! '});
}
userObject.validatePassword(password, foundUser.password, function(error,found){
if(found) return done(null, foundUser)
else done(null, false, {msg : 'Auhentication failed, Invalid Password !! '});
})
});
}
));
So the first line of our code is basic syntax of passport object which tells passport which strategy has been used and accordingly, the object will be created, like in our example, we are using passport-local
strategy, so the object we have created is PassportLocal
. It was a basic fix syntax, and the next line as well, which provides username and password from vie. Our work starts from the next line, so we have username and password data in our router file. Now what we will do is we will make a call to the database and try to get the user based on username. Remember when we have created schema, we kept username as index.
Traverse to user.js file that is dao layer of our application. In this file, we will be creating a function to fetch user data from database.
module.exports.findByUsername = function(username, callback){
User.findOne({username:username},callback);
}
So we made a call to database with query username
. It will return the user data for the usename
we have passed in the query, and the same function is called from our router. Now, the below piece of code:
function(error, foundUser){
if(error) throw error;
if(!foundUser){
done(null, false, {msg : 'Auhentication failed, Invalid Username !! '});
}
That is in the router post
method for login, will check if there is any error or not, if there is any error, error will be displayed on page and it will be redirected to the URL that we have provided. If there is no data in foundUser
, (foundUser
is just a parameter name, that we got as callback from dao layer) i.e., there is no data present in database corresponding to the username. So if there is no data, we will throw an error message as 'Authenticaion failed, Invalid Username!!
'. If there is data present in database corresponding to the username, the next step is to validate password. So again, we will go to dao layer and write a method that will have code to validate password.
One more interesting thing here to notice, if you can remember, we have saved our password in encrypted from using sha512 crypto algorithm. Now the glitch is that we cannot decrypt the password, once encrypted, it's encrypted, so how will we compare and check the passwords now and how will we authenticate the user. To overcome this, what we will do is we will encrypt the password with the same sha512 algorithm and then compare both the passwords. Let's write code for this:
module.exports.validatePassword = function(password, foundPasswordHash, callback){
var hash = generateHash(password);
var pwHash = hash.passwordHash;
if(pwHash==foundPasswordHash){
callback(null,true);
}else {
callback(null, false);
}
}
So the most important part is to generateHash
here, we have reused the same method that we have created at the time of registration for hashing. If both hashes are the same, then we will be passing true
to router and if not, then we will pass false
.
One more thing that we need to do is, when user logs in, we will display welcome message with his name, so we need user's name on view part as well. Also once user is logged in, he should not be able to see the Register and Login links. And when user is logged out, he should not see the Home and Logout link.
To achieve this, we need to modify our main.js file and add local for user as well. Let's add this:
res.locals.user = req.user || null;
in app.use
method, where we are setting flash messages, we will add this line. Now at view part, we will use this local to show hide links.
{{#if user}}
<li role="presentation"><a href="/">Home</a></li>
<li role="presentation"><a href="/users/logout">Logout</a></li>
{{else}}
<li role="presentation"><a href="/users/login">Login</a></li>
<li role="presentation"><a href="/users/register">Register</a></li>
{{/if}}
So we will add this check in our layout file. The code says that if user is null
that we are setting in main.js then user is not logged in and he is good to go with Register and login links.
Note: In order to keep things simple, we didn’t beautify the application but that can be easily done using bootstrap framework. You can find all about bootstrap framework here.
In index view, we are going to use the user object to fetch user's name to display welcome message:
<h4 class="text-muted">Welcome {{user.name}} to Online bookstore,
Below is the list of books you recently purchased.</h4>
Let's test with putting it all together. For that, we need to restart the server again. Let's restart and test.
So we are trying to login user Ahmad
, let's see if Ahmad
can login to our system:
Alright, so Ahmad is successfully logged in and he can see the recent orders he placed with our online book store.
Last thing is to check logout functionality. Let's check:
Alright, everyting is working fine, well and good. So it completes this tutorial for MEAN stack user registration and login module.
More MEAN Stack and Related Tutorials
The post Building your first MEAN Stack Web Application – Part2 appeared first on Web Development Tutorial.