Session management is a major piece of any serious web application. When building a site, it is likely you will want the ability to persist a user's identity over multiple requests without having to have them re-login again and again. A common method for persisting a user's login over multiple http requests, is called setting a "cookie". Now almost all web developers have some idea of what a cookie is, but in this article we will dive into the specifics of actually implementing a cookie / session persistence system from scratch in node.js through exploring the session.js library and the response library.
Getting Started
First, we are going to need some logic for implementing session management. Crack JavaScript developer inimino was nice enough to release the following module, so we will build on that. In this module, only one method is exported: "lookupOrCreate". If we dive into this method a little bit, we can see it takes two options, a request object and an options hash.
This "lookupOrCreate" method will inspect the headers of the incoming request object and determine if there is any value set for the cookie field ( note: the actual header name is "Set-Cookie", but node refers to this header as "cookie"). If lookupOrCreate finds a cookie, it will retrieve the session object from memory, else it will create a new session for that request.
Now, the tricky part here is that if we've created a new session, we need to set the cookie in the response header so the client knows it has a session. Unless we explicitly set a cookie in the response header, "lookupOrCreate" will never find your session cookie.
To set the cookie in the http response you can do something like:
var session = sessions.lookupOrCreate(request,{
lifetime:604800
});
response.writeHead(200, {
'Content-Type': 'text/plain',
'Set-Cookie', session.getSetCookieHeaderValue()
});
Even better then using response.write though, is using response.setHeader. This will not close the response, and allow for further manipulation down the request/response processing chain...kinda like a proper middle-ware!
response.setHeader('Set-Cookie', session.getSetCookieHeaderValue());
Note: You will need the response module for this to work, it should be pulled into core eventually.
Creating a super simple session middle-ware
In node.js, an accepted standard for building middleware is the following:
function( request, response, callback) {
// perform some logic on the request or response objects
console.log(request.url);
// then fire our callback, and pass the request
// and response objects down the chain
callback(request, response, function(){
});
}
Following this standard, a "middle-ware" for node.js's httpServer is nothing but a function that accepts three arguments: a request object, a response object, and a callback. Building on this very simple convention, we can implement de-coupled layers of middleware, each with its own responsibility. In our case, our middleware will be responsible for establishing sessions!
get session.js!
Using session.js as a middle-ware
var http = require('http'),
session = require('./lib/core').session;
// let's create a basic http server!
http.createServer(function (request, response) {
// before we process any part of the request, let's use the session middle-ware!
session(request, response, function(request, response){
// now we can access request.session
// after the session middleware has executed, let's finish processing the request
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('request.session: \n' + JSON.stringify(request.session, 2, true));
response.end();
});
}).listen(8080);
/* server started */
console.log('> hello world running on port 8080');
Magic Monkey Punched Middle-ware Sessions (automatically patches httpServer)
Creating a super simple login / logout feature
One of the best things about having a persistent session object per user, is having the ability to create user logins. The actual way you want to implement your login is somewhat arbitrary. Here is a basic pattern to follow. Please, remember this method is just an example:
var http = require('http'),
session = require('./lib/core').magicSession();
// let's create a basic http server!
http.createServer(function (request, response) {
// please note: this is just an example of how to hook auth into session.js, its not ideal at all
// super basic logout
if(request.url === '/logout'){
request.session.data.user = "Guest";
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('You\'ve been logged out');
response.end();
return;
}
// let's hardcode a username and password variable into the url
var urlParams = require('url').parse(request.url, true).query || {};
if(typeof urlParams.name != 'undefined'){
// if the "name" parameter has been sent, lets log in as that user
request.session.data.user = urlParams.name;
}
// request.session.data.user always defaults to "Guest"
if(request.session.data.user == "Guest"){
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('Hello, you are the Guest user');
response.end();
}
else{
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('Hello, you are ' + request.session.data.user);
response.end();
}
}).listen(8080);
/* server started */
console.log('> hello world running on port 8080');Once you have this running you can do the following:
GET http://localhost:8080/
// returns: Hello, you are the Guest user
GET http://localhost:8080/?name=Marak
// returns: Hello, you are Marak
GET http://localhost:8080/
// returns: Hello, you are Marak
GET http://localhost:8080/logout
// returns: You've been logged out
GET http://localhost:8080
// returns: Hello, you are the Guest user
Huzaah! There you go! session.js is open-source, so lets get hacking!