User login and registration with nodejs using Express, Bycrpt and MySql

in #nodejs6 years ago (edited)

Today we’re going to learn how to implement simple user authentication in a nodejs application from scratch.

Introduction to User Authentication

Password protected actions are common in all types of applications , mainly web applications which we are now going to see. To access protected actions is allowed for only registered users need a valid password. This is called "User Authentication" and many Node applications. Let's start with a quick overview of how user authentication work.

  • Register(Signup): Create a new user, by providing username , email and password (password here will be encrypted).
  • Login: allows a user to signin with his valid email and password to access the password protected actoons of out web application.
  • Access Restriction: create a session to hold the authenticated user email after login, so navigation through additional protected actions can be done easily by just checking the email the current session.
  • Logout: allow the user to sign out and set the authenticated email in session file to blank.

Lets start building our node application

Create a folder with name of you application (example: "BasicAuth")

Go into this folder and enter

npm init

Keep pressing enter and let everything be default, now lets install the dependencies which we need

npm install express express-session bcrypt body-parser sequelize sequelize-cli mysql2 ejs --save

the above command will install all the dependencies which we need to make a full nodejs user authentication application. Overview of dependencies which we have installed just now.

  • express: its a very famous module used for creating web applications with nodejs
  • express-session: This will help us to store and access sessions in web browsers cookies. This sessions are used to track which user is currently logged in.
  • bcrypt: This is used to covert user's password to hash which we will be storing in the database rather than the real password.
  • ejs: it is a view engine which we will be using to write html pages and with this ejs we can add node code in the pages and access variables passed down from action methods in our controllers.
  • sequelize and seqeulize-cli: this is an ORM which we will be using to manage models , write migrations etc
  • mysql2: this is used by our sequelize to comminicate with mysql server, which we need to store data.

Lets start creating our application

First we need to create a database and a user table in our database to store details of our users.

node_modules/.bin/sequelize init

this will create a basic structure to create migrations, models etc. Lets now create a User table migration and model corresponding to it.

node_modules/.bin/sequelize model:generate --name User --attributes username:string,email:string,password:string

Now we can see a file in models folder with name user.js has been created and another file in migrations folder which will create a table named user in out mysql database.

Before creating out user table , lets create a database in our mysql server.
Go to config/config.json file and edit username and password to your mysql server credentials and also change the database name if you want to under development, test and production.

Creation of our database in mysql server

node_modules/.bin/sequelize db:create

this will create our database

Creating User table in our database

node_modules/.bin/sequelize db:migrate

this will create user table in our database, go ahead and check it out.

Let create Controllers to handle login and register

Here first we create a new folder controllers and a file named `account_controller.js' . This file will handle our login and registration process i.e this file will take login credentrials and check it with our User table and while registration this will add our new user to the table .

first import neccessary modules

var express = require('express');
var bodyParser = require('body-parser');
var ejs = require('ejs');
var path = require('path');
var session = require('expr`ess-session');
var models = require('../models');
var Sequelize = require('sequelize');
const bcrypt = require('bcrypt');

now lets create an accountRoutes

var accountRoutes = express.Router();

now create routes to show registeration page and login page to enter details

accountRoutes.get('/login',function(req,res){
    res.render('account/login');
});
accountRoutes.get('/register',function(req,res){  
    res.render('account/register',{errors: ""});
});

the above res.render method will render the pages which we will after few moments in views/account. We will create two pages login.ejs and register.ejs.

Now lets handle the creation or registration of a new user when the user enters his details and submits in views/ account/register.ejs

accountRoutes.post('/register',function(req,res){
    var matched_users_promise = models.User.findAll({
        where:  Sequelize.or(
                {username: req.body.username},
                {email: req.body.email}
            )
    });
    matched_users_promise.then(function(users){ 
        if(users.length == 0){
            const passwordHash = bcrypt.hashSync(req.body.password,10);
            models.User.create({
                username: req.body.username,
                email: req.body.email,
                password: passwordHash
            }).then(function(){
                let newSession = req.session;
                newSession.email = req.body.email;
                res.redirect('/');
            });
        }
        else{
            res.render('account/register',{errors: "Username or Email already in user"});
        }
    })
});

In the above code, we will check if a user is already registered with same email and username, if not we will go ahead and store this user details in our user table. For creating the session we will store email of the user to distinguish which user is logged in . The session is stored in browser cookies so everyone has there own sessions. If everything goes good we create the user session( that means how this user is logged in) and redirect him to our home page at route /

Now lets handle the login of a registered user when the user enters his email and password and submits in views/ account/login.ejs

accountRoutes.post('/login',function(req,res){
    var matched_users_promise = models.User.findAll({
        where: Sequelize.and(
            {email: req.body.email},
        )
    });
    matched_users_promise.then(function(users){ 
        if(users.length > 0){
            let user = users[0];
            let passwordHash = user.password;
            if(bcrypt.compareSync(req.body.password,passwordHash)){
                req.session.email = req.body.email;
                res.redirect('/');
            }
            else{
                res.redirect('/register');
            }
        }
        else{
            res.redirect('/login');
        }
    });
});

Now here in the request object we have both email and password entered by the user in views/account/login.ejs, Now what we are doing here is getting the User from our database who has same email address and comparing the entered password with the password hash stored in our database. Since we cant directly compare the entered password with the password hash stored in our database . We are using bcrypt.compareSync(req.body.password,passwordHash) which will covert our entered password to password hash and then it compares this resultant password hash with the password hash stored in our database , if we get true then the password is matched. After authenticating the user credentials we proceed and create session which stores the user email address in it like this req.session.email = req.body.email.

At the end of this file i.e controllers/account_controller.js write this code to export our routes such that in server.js we can use these routes or make them accessable.

module.exports = {"AccountRoutes" : accountRoutes};

Login and Registration pages

Login page
Now lets create our login page , create a new folder names views .Now create folder names account inside views folder. FInally we will create a new file named login.ejs in account folder. So the path of our login.ejs is views/account/login.ejs.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="BasicAuth">
    <meta name="author" content="siddub">

    <title>BasicAuth</title>

     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/5.1.1/bootstrap-social.min.css" rel="stylesheet" crossorigin="anonymous">

</head>

<body>

<div class="container">
  <form method="POST" action="/login"  >
      <h2>Log in </h2>

      <input name="email" type="text" class="form-control" placeholder="Email Address"
              autofocus="true"/>
      <input name="password" type="password" class="form-control" placeholder="Password"/>

      <button class="btn btn-lg btn-primary btn-block" type="submit">Log In</button>
          
      <div style="align-text:center;margin-bottom:10px;margin-top:15px"> Don't have an account? <a href='/register'>Sign up</a></div>
    
  </form>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="${contextPath}/resources/js/bootstrap.min.js"></script>
</body>
<style>
input{
  margin-bottom: 15px
}
h2{
  text-align: center
}
.container{
  width:50%
}
</style>
</html> 

register page
create a new file register.ejs in views/account folder and paste the code written below

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta name="description" content="BasicAuth">
    <meta name="author" content="siddub">

    <title>BasicAuth</title>
  <title>Create a Jangle account</title>  (html comment removed:  Latest compiled and minified CSS )
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>

<body>
<%= errors %>
<div class="container">
      <form class="login-form" method="POST" action="/register"  >
        <h2 class="form-heading">Create your Account</h2>
        <input name="username" type="text" class="form-control" placeholder="Username" autofocus="true"/>
        <input name="email" type="text" class="form-control" placeholder="Email" autofocus="true"/>
        <input name="password" type="password" class="form-control" placeholder="Password" />
        <input name="passwordConfirm" type="password" class="form-control" placeholder="Password confirm" />

        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign up</button>
      </form>

</div>
(html comment removed:  /container )
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>


<style>
input{
  margin-bottom: 15px
}
h2{
  text-align: center
}
.container{
  width:50%
}
</style>

</body>
</html>

it seems straight forward what we did in login.ejs and register.ejs pages is to create a folrm and submit those form values when to /login and /register routes in POST method.

Now the main step is to write our server.js file to run our server

Now create a file named server.js in our main folder if this file is not present. Now inside this file we will setupour environment and add routes needed. We provide a port number to run the server.

first, let's require dependencies which we need in our server.js file

var express = require('express');
var bodyParser = require('body-parser');
var session = require('express-session');

Now import or require the account route which we have written in controllers/account_controller

var AccountRoutes = require('./controllers/account_controller');

Now lets declare and assign a port variable

var port = process.env.PORT || 3000;

Now lets configure express

app.set('view engine','ejs');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

Now lets give a session secret which is needed to add a level of extra security, The session we will store in client's browser cookies is encrypted using our session secret and only our web application which knows the session secret can read the session which we will create to store the current logged in user's email address.

app.use(session({secret: 'randomstringsessionsecret'}));

here I have given 'randomstringsessionsecret' as session secret, feel free to give any string as a session secret.

Now lets include our routes which we created in account_controller.js to our application.

app.use('/',AccountRoutes.AccountRoutes);

now lets make our server listen or use port number which we assigned it to a port variable

app.listen(port);

Now we need to run the server.
open upthe cmd or terminal and enter

 node server.js 

now we will open a browser and go to `localhost:3000/register' .
here we will create a user and when we go to user table in our database in MySQL server, we will see that the user details we entered are stored and the password is converted into some large string which is the password hash.

Time to create a Homepage

Now we will create a homepage which is password-restricted and only valid users after loggin can view this home page
To accomplish this we need

  • a home page
  • we need to create a route which renders our home page
  • we need to restrict this homepage only to logged in user

Creating Home controller
now lets create a new home controller which handles / route which is our home page route.

var express = require('express');
var bodyParser = require('body-parser');
var ejs = require('ejs');

var path = require('path');
var HomeRoutes = express.Router();

var correct_path = path.join(__dirname+'/../views/home/');
HomeRoutes.get('/',function(req,res){
    let email = req.session.email;
    res.render('home/index',{user_email: email});
});

module.exports = {"HomeRoutes" : HomeRoutes};

Creating home page
Now we need to create our home page, inside views folder create a new folder named home. Now in this home folder create a new file named index.ejs

<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta name="description" content="BasicAuth">
    <meta name="author" content="siddub">
    <title>BasicAuth</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  </head>
  <body class="container" style="width:98%">
    <h1>welcome, logged in as <%= user_email %></h1>
  </body>
</html>

Now in this page we will see the email of the logged in user.


Since we need to make this home page available to a logged in user.We will write a middleware which will restrict or make home page unavailable when users are not logged in.

open server.js file which we have used before and add this code

var HomeRoutes = require('./controllers/home_controller');

just below the line where we declared and assgined AccountRoutes variable

Now just above app.listen(port) add

app.use(function(req,res,next){
  if(req.session.email == null || req.session.email.length ==0 ){
      res.redirect('/login'); 
  }
  else{
    next();
  }
});
app.use('/',HomeRoutes.HomeRoutes);

the above middleware code will check if the user is logged in by checking if email a user is present in the session. If the email is present some value then we will proceed with this request and if the user is not logged in we will redirect to login page.

Now by this our application is complete and now proceed to start our application by entering the below command in cmd or terminal.

node server.js

Now open localhost:3000 in a browser.

Register page

Screenshot from 2019-01-21 19-34-29.png

Login page

Screenshot from 2019-01-21 19-35-25.png

After login open home page and it looks like this

Screenshot from 2019-01-21 19-36-43.png

Sort:  

Hello @siddub! This is a friendly reminder that you have 3000 Partiko Points unclaimed in your Partiko account!

Partiko is a fast and beautiful mobile app for Steem, and it’s the most popular Steem mobile app out there! Download Partiko using the link below and login using SteemConnect to claim your 3000 Partiko points! You can easily convert them into Steem token!

https://partiko.app/referral/partiko

Congratulations @siddub! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 1 year!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!