Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Socket IO only session not persisting

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?

like image 969
Drown Avatar asked Jan 15 '16 02:01

Drown


2 Answers

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.

  • How to share sessions with Socket.IO 1.x and Express 4.x?
  • https://www.npmjs.com/package/express-socket.io-session
  • https://github.com/rakeshok/socket.io-client-cookie
  • http://www.w3.org/TR/XMLHttpRequest/
  • https://github.com/socketio/socket.io/blob/master/examples/chat/index.js#L35-L36
  • How to associate properties to socket.io object in Redis Store?
like image 173
Deividy Avatar answered Sep 19 '22 21:09

Deividy


  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
    });
}
like image 23
Nazar Sakharenko Avatar answered Sep 17 '22 21:09

Nazar Sakharenko