Search This Blog

Friday, February 23, 2018

Using Redis as Session Store In Express.js

http protocol  being stateless,to maintain state across multiple request from client  to server usually cookies & sessions as used along to URL params.
Cookies get stored in client browser,it has been assigned expiry time.Untill cookies from given server is alive it get passed to server in every subsequent request

As cookies are on client we need to obsure it using some sort of hashing algorithm.otherwise person with malicious intent will tamper it.

   'Express-session' is more abstract compared to cookie-based, it supports different session stores like files, DB, cache on contratory 'cookie-session' is a simple & lightweight ,
it support only cookie storage engine.Meaning in cookie-session all the session info is stored on the client in a cookie.
     'Express-session' stores just a mere session identifier within a cookie in the client end, whilst storing the session data entirely on the session store.

UUIDs are for practical purposes unique, without depending for their uniqueness on a central registration authority or coordination between the parties generating them, unlike most other numbering schemes. While the probability that a UUID will be duplicated is not zero, it is close enough to zero to be negligible.We are using uuid for creating unique session id.

Redis is in memory key-value pair database,retrieval data in case of redis is faster compared to RDBMS as its in memory compared to in Disk.

Lets see how we can use redis to store session.First we need install required packages express-session,connect-redis,redis,uuid.

In our existing express.js project created using express generator  inside app.js add

    var session = require('express-session');
    var redisStore = require('connect-redis')(session);

    var redis   = require("redis");
   //var client  = redis.createClient();

    const redisPassword = "sangram";
    var client = redis.createClient({
     host: '127.0.0.1',
     no_ready_check: true,
    auth_pass: redisPassword,
   });
   



    var uuid = require('uuid/v4')


now add middleware which will attach redisstore as session store in express-session

app.use(session({
  genid: function(req) {
    var uid = uuid() 
    console.log('UId :' + uid);
    return uid;
  },
  secret: 'my_secret',
  // create new redis store.
  store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl :  260}),
  saveUninitialized: false,
  resave: false
}));


Here genid function is giving unique ids to session for new session of client.

Create a Login Page login.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <form method="POST" action="/login">
      <table style="border:1px solid red;background-color:skyblue;color:white;">
        <tr>
          <td colspan="2">
            Login to express demo
          </td>
        </tr>
        <tr>
          <td>Username</td>
          <td>
            <input type="text" name="username" id="username" required />
          </td>
        </tr>
        <tr>
          <td>password</td>
          <td>
            <input type="password" name="password" id="password" required />
          </td>
        </tr>
        <tr>
          <td></td>
          <td>
              <input type="submit" value="Login" style="background-color:orange" />
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>

also create a dummy view for authentication home

authhome.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <%= username %>
  </body>
</html>

then create route for login in routes/index.js

router.get('/login', function (req, res, next) {
  res.render('login', { title: 'login' });
});


router.get('/bar', function (req, res, next) {
  req.session.city = 'Mumbai';
  console.log("Bar:city:" + req.session.city);
  res.redirect('/authhome')
});

router.get('/authhome', function (req, res, next) {
  console.log("AuthHome:city:" + req.session.city);
  res.render('authhome', { title: 'auth-home', username: req.session.username,city: req.session.city });
});

router.post('/login', function (req, res, next) {
  req.session.username = req.body.username;
  req.session.city = 'Mumbai';
  res.redirect('/authhome')
});

router.post('/logout', function (req, res, next) {
  req.session.destroy(function (err) {
    if (err) {
      console.log(err);
    } else {
      res.redirect('/home')
    }
  });

});


Now visit http://localhost:3000/ & using your browser developer tool confirm no cookies set by http://localhost:3000/,
To create session & hence cookie Visit http://localhost:3000/login still no cookie set.

Now provide some dummy username & password & submit,it will not validate credential as it is not put in place put will add 'username' to session.
After setting this value user is redirected to http://localhost:3000/authhome which print username saved in session.While City will be empty.

Now hit http://localhost:3000/bar in new tab ,this GET request set 'city' key in session. After setting this value user is redirected to http://localhost:3000/authhome
Here both username & city are displayed on View.

Refresh previous tab it will also show username & city in view.

If you repeat same using other browser you will see different session ids are generated & 'username' value stored in session is not overlapping with each other.

To see keys generated in redis launch redis-cli on terminal.'KEYS *' will list all keys .

Using one of key printed in 'Keys *' output say 'sess:5d5ee6f0-c835-4672-a3f2-f201f51e46b7' you can see cookies set to client browser run below command in redis-cli

    GET sess:5d5ee6f0-c835-4672-a3f2-f201f51e46b7
        output:
        "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"username\":\"sangram\",\"city\":\"Mumbai\"}"


'flushdb' is used to remove all keys in current database.

You can cross verify keys with those printed on console from session middleware function 'genid' for generating unique session id.

Code of this article can be viewed at https://github.com/gitsangramdesai/redis-session-store-express

No comments:

Post a Comment