Friday, February 17, 2017

ExpressJS - Authentication

Authentication is a process in which the credentials provided are compared to those on file in a database of authorized users' information on a local operating system or within an authentication server. If the credentials match, the process is completed and the user is granted authorization for access.

For us to create an authentication system, we will need to create a sign up page and a user-password store. The following code creates an account for us and stores it in memory. This is just for demo purposes, ALWAYS use a persistent storage(database or files) to store user information.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer(); 
var session = require('express-session');
var cookieParser = require('cookie-parser');

app.set('view engine', 'pug');
app.set('views','./views');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); 
app.use(upload.array());
app.use(cookieParser());
app.use(session({secret: "Your secret key"}));

var Users = [];

app.get('/signup', function(req, res){
    res.render('signup');
});

app.post('/signup', function(req, res){
    if(!req.body.id || !req.body.password){
        res.status("400");
        res.send("Invalid details!");
    }
    else{
        Users.filter(function(user){
            if(user.id === req.body.id){
                res.render('signup', {message: "User Already Exists! Login or choose another user id"});
            }
        });
        var newUser = {id: req.body.id, password: req.body.password};
        Users.push(newUser);
        req.session.user = newUser;
        res.redirect('/protected_page');
    }
});

app.listen(3000);
Now for the signup form, create a new view called signup.jade.

signup.jade

html
    head
        title Signup
    body
        if(message)
            h4 #{message}
        form(action="/signup" method="POST")
            input(name="id" type="text" required placeholder="User ID")
            input(name="password" type="password" required placeholder="Password")
            button(type="Submit") Sign me up!
Test that this page loads by visiting localhost:3000/signup
Signup form We have set the required attribute for both fields, so HTML5 enabled browsers won't let us submit this form until we provide both id and password. If someone tries to register using a curl request without a User ID or Password, the error will be showed to him. Create a new file called protected_page.pug in views with the following content:
html
    head
        title Protected page
    body
        div Hey #{id}, How are you doing today?
        div Want to log out?
        div Logout
This page should only be visible if the user has just signed up or logged in. So lets define its route as well as routes to log in and log out:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer(); 
var session = require('express-session');
var cookieParser = require('cookie-parser');

app.set('view engine', 'pug');
app.set('views','./views');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); 
app.use(upload.array());
app.use(cookieParser());
app.use(session({secret: "Your secret key"}));

var Users = [];

app.get('/signup', function(req, res){
    res.render('signup');
});

app.post('/signup', function(req, res){
    if(!req.body.id || !req.body.password){
        res.status("400");
        res.send("Invalid details!");
    }
    else{
        Users.filter(function(user){
            if(user.id === req.body.id){
                res.render('signup', {message: "User Already Exists! Login or choose another user id"});
            }
        });
        var newUser = {id: req.body.id, password: req.body.password};
        Users.push(newUser);
        req.session.user = newUser;
        res.redirect('/protected_page');
    }
});

function checkSignIn(req, res, ){
    if(req.session.user){
        next();     //If session exists, proceed to page
    } else {
        var err = new Error("Not logged in!");
    console.log(req.session.user);
        next(err);  //Error, trying to access unauthorized page!
    }
}

app.get('/protected_page', checkSignIn, function(req, res){
    res.render('protected_page', {id: req.session.user.id})
});

app.get('/login', function(req, res){
    res.render('login');
});

app.post('/login', function(req, res){
    console.log(Users);
    if(!req.body.id || !req.body.password){
        res.render('login', {message: "Please enter both id and password"});
    }
    else{
        Users.filter(function(user){
            if(user.id === req.body.id && user.password === req.body.password){
                req.session.user = user;
                res.redirect('/protected_page');
            }
        });
        res.render('login', {message: "Invalid credentials!"});
    }
});

app.get('/logout', function(req, res){
    req.session.destroy(function(){
        console.log("user logged out.")
    });
    res.redirect('/login');
});

app.use('/protected_page', function(err, req, res, next){
console.log(err);
    //User should be authenticated! Redirect him to log in.
    res.redirect('/login');
});

app.listen(3000);
We have created a middleware function checkSignIn to check if the user is signed in. The protected_page uses this function. To log the user out we destroy the session.
Let's now create the login page. Name the view as login.pug and enter the contents:
html
    head
        title Signup
    body
        if(message)
            h4 #{message}
        form(action="/login" method="POST")
            input(name="id" type="text" required placeholder="User ID")
            input(name="password" type="password" required placeholder="Password")
            button(type="Submit") Log in
Our simple authentication application is now complete, so lets test it out! Run the app using nodemon index.js, and proceed to localhost:3000/signup
Enter a Username and a password and click sign up. You'll be redirected to protected_page if details are valid/unique:
Protected page Now log out of the app. This will redirect us to the login page:
Auth login Our route is protected such that if an unauthenticated person tries to visit it, she'll be redirected to our login page. This completes all about basic user authentication. The way we authenticated users is very unsecure. You should always use a persistent session system and use hashes for password transport. There are much better ways to authenticate users now, leverating JSON tokens.

No comments:

Post a Comment