angry_kiwi angry_kiwi - 4 months ago 26
Node.js Question

nodeJS - How to create and read session with express

I want to create a user sessison when user enter the app. And read the session whenever needed. Here is my try

var io = require('socket.io'),
express = require('express');
querystring = require('querystring');

var app = express.createServer();
app.get('/', function(req, res){
var sessionVal = querystring.parse(req.url.substr(2));// sessionVal is an email for example: me@gmail.com
app.use(express.cookieParser());
app.use(express.session({ secret: sessionVal }));
});
var socket = io.listen(app);
socket.on('connection', function(client) {
client.on('message', function(message) {
// message will be an object {text:'user text chat blah blah', email:'me@gmail.com'}
// if the seesion stored, has the same value with message.email
// then the message will be broadcasted
socket.broadcast(message.text);
// else will not broadcast
});
});

app.listen(4000);

Answer

I need to point out here that you're incorrectly adding middleware to the application. The app.use calls should not be done within the app.get request handler, but outside of it. Simply call them directly after createServer, or take a look at the other examples in the docs.

The secret you pass to express.session should be a string constant, or perhaps something taken from a configuration file. Don't feed it something the client might know, that's actually dangerous. It's a secret only the server should know about.

If you want to store the email address in the session, simply do something along the lines of:

req.session.email = req.param('email');

With that out of the way...


If I understand correctly, what you're trying to do is handle one or more HTTP requests and keep track of a session, then later on open a Socket.IO connection from which you need the session data as well.

What's tricky about this problem is that Socket.IO's means of making the magic work on any http.Server is by hijacking the request event. Thus, Express' (or rather Connect's) session middleware is never called on the Socket.IO connection.

I believe you can make this work, though, with some trickery.

You can get to Connect's session data; you simply need to get a reference to the session store. The easiest way to do that is to create the store yourself before calling express.session:

// A MemoryStore is the default, but you probably want something
// more robust for production use.
var store = new express.session.MemoryStore;
app.use(express.session({ secret: 'whatever', store: store }));

Every session store has a get(sid, callback) method. The sid parameter, or session ID, is stored in a cookie on the client. The default name of that cookie is connect.sid. (But you can give it any name by specifying a key option in your express.session call.)

Then, you need to access that cookie on the Socket.IO connection. Unfortunately, Socket.IO doesn't seem to give you access to the http.ServerRequest. A simple work around would be to fetch the cookie in the browser, and send it over the Socket.IO connection.

Code on the server would then look something like the following:

var io      = require('socket.io'),
    express = require('express');

var app    = express.createServer(),
    socket = io.listen(app),
    store  = new express.session.MemoryStore;
app.use(express.cookieParser());
app.use(express.session({ secret: 'something', store: store }));

app.get('/', function(req, res) {
  var old = req.session.email;
  req.session.email = req.param('email');

  res.header('Content-Type', 'text/plain');
  res.send("Email was '" + old + "', now is '" + req.session.email + "'.");
});

socket.on('connection', function(client) {
  // We declare that the first message contains the SID.
  // This is where we handle the first message.
  client.once('message', function(sid) {
    store.get(sid, function(err, session) {
      if (err || !session) {
        // Do some error handling, bail.
        return;
      }

      // Any messages following are your chat messages.
      client.on('message', function(message) {
        if (message.email === session.email) {
          socket.broadcast(message.text);
        }
      });
    });
  });
});

app.listen(4000);

This assumes you only want to read an existing session. You cannot actually create or delete sessions, because Socket.IO connections may not have a HTTP response to send the Set-Cookie header in (think WebSockets).

If you want to edit sessions, that may work with some session stores. A CookieStore wouldn't work for example, because it also needs to send a Set-Cookie header, which it can't. But for other stores, you could try calling the set(sid, data, callback) method and see what happens.