10

I'm using Socket.io in a chat application I'm building. I'm trying to setup the session so that I can persist the login of the users in between sessions.

Here's the relevant code :

index.js (server)

var cookieParser = require('cookie-parser')();
var session = require('cookie-session')({ secret: 'secret' });

app.use(cookieParser);
app.use(session);

io.use(function(socket, next) {
    var req = socket.handshake;
    var res = {};
    cookieParser(req, res, function(err) {
        if (err) return next(err);
        session(req, res, next);
    });
});


io.on('connection', function(socket){

    socket.on('test 1', function(){
        socket.handshake.test = 'banana';
    });

    socket.on('test 2', function(){
        console.log(socket.handshake.test);
    });
});

chat.js (client)

var socket = io();

socket.emit('test 1');
socket.emit('test 2');

The code above works, it will print banana to the console as expected. However, if I comment out the 'test 1' like so :

var socket = io();

// socket.emit('test 1');
socket.emit('test 2');

It will print undefined to the console.

Shouldn't it still be able to print banana, since it's using a session and it's persisting between requests? I also run into the same issue if I inverse the order in which I call 'test 1' and 'test 2'.

What am I doing wrong? What am I missing for the session to persist as expected?

Drown
  • 5,280
  • 1
  • 24
  • 45
  • Does using `socket.handshake.session.test = 'banana';` for `test 1` and `socket.handshake.session.test` for `test 2` work? – Ash Jan 18 '16 at 02:48

2 Answers2

6

The problem is that you are using a cookie-session, and socket.io does not allow you to set cookies due specification of XMLHttpRequest, also you don't have a request/response in the middle of a web socket transaction, so you cannot set the response cookie.

With your middleware, you can see the cookies, but you cannot set it in socket.io. This can be ensured with this example:

io.use(function(socket, next) {
    var req = socket.request;
    var res = req.res;
    cookieParser(req, res, function(err) {
        if (err) return next(err);
        session(req, res, next);
    });
});

io.on('connection', function(socket){
    var req = socket.request;
    console.log(req.session.test)

    socket.on('test 1', function(){
        req.session.test = 'banana';
    });

    socket.on('test 2', function(){
        console.log(req.session.test);
    });
});

app.get('/', function(req, res) {
    console.log(req.session.test)
    if (!req.session.test) {
      req.session.test = 'banana request'
    }
})      

You can use something like redis to persist the sessions, or some 'hack' to set it in the handshake.

Another option is not use sessions at all, and just set the property in socket object or in another javascript object, but in this case you cannot share the object between servers/services.

Community
  • 1
  • 1
Deividy
  • 809
  • 6
  • 7
1
  1. There is still access to headers.
  2. You can save data on server side for each socket: socket.my_value = "any data type";
  3. You can save data in io.sockets object, io.my_value = "any data type"

So, example:

    io.on('connection', function(socket){
        var id = socket.handshake.query.id; //you can set this in client connection string http://localhost?id=user_id
        //Validate user, registered etc. and if ok/
        if(validateUser(id)) {
            //if this is reconnect
            if(io.sessions[id]) {
               socket.session_id = io.sessions[id].session_id;
            } else {
               var session_id = random_value;
               socket.session_id = some_random_value;
               io.sessions[id] = {
                 user_id: id,
                 session_id: socket.session_id
               };
            }

            registerEvent(socket);
        } else {
            socket.emit('auth_error', 'wrong user');
        }
    });


function registerEvent(socket) {
    socket.on('some_event', function(data, callback) {
       if(!socket.session_id) {
         callback('unathorized');//or emit
         socket.emit('auth_error', 'unauthorized');
       }

       //do what you want, user is clear
    });
}
Nazar Sakharenko
  • 937
  • 5
  • 11