Using Sessions with Express.js v4 and Socket.io v1

How to save session data in express.js and access it inside socket.io events?

I am developing webapp using express.js v4 , socket.io v1 and basic express-session .

I spent several hours trying to figure this out, but all the current answers on Stack apply only to v3 expression and socket.io v0.9. Unfortunately, I cannot use express.io, because it is just a shell using these old versions.

My current solution is a complete hack:

app.get('/auth', function(req, res) { if(verified(req.query)) { authed[req.sessionID] = true; } }); io.sockets.on('connection', function(websocket) { var cookies = cookie.parse(websocket.handshake.headers.cookie); var decrypted = cookieParser.signedCookies(cookies, random); var sessionID = decrypted['connect.sid']; websocket.on('input', function(input) { if(authed[sessionID]) { // Do stuff... } }); }); 

I save my “session data” in the object as a key / value store based on session identifiers. This is great for single-process applications, but it's really not a good solution. This actually does not give me access to anything stored in req.session, and all my saved data will be lost if the process ends.

Among other things, I need to download a third-party cookie package to parse the cookie string from socket.io. It seems that the new version of cookie-parser has removed its function for analyzing cookies from a string. At least this is not documented.

There has to be a better way!

Edit: In the end, I decided to use express redis and wrote a function in socket.io to get information from redis based on the session ID.

+6
source share
2 answers

You can either save sessions in Memcached or Redis. You can then retrieve session data from one of these repositories.

Both memcache and redis packages are available for nodejs.

Also note that you can use middleware for authentication in socket.io. Then you do not need to insert authentication logic into the connection event handler.

 var authorization = require('./socket/authorization')(app); io.use(authorization.authorize); 

And as an example of this memcached auth file, which in our case reads a cookie stored on our php.

 var memcached = require('memcached'), cookie = require('cookie), debug = require('debug')('socket.io:authorization'); module.exports = function(app) { var authorize = function(socket, next) { var handshakeData = socket.request; if (handshakeData.headers.cookie) { handshakeData.cookie = cookie.parse(handshakeData.headers.cookie); if (typeof handshakeData.cookie['node'] === 'undefined') { next(new Error('No cookie transmitted.')); } else { var loginEndIndex = handshakeData.cookie['node'].indexOf(','); handshakeData.node = handshakeData.cookie['node'].slice(0, loginEndIndex); var memcached = new Memcached(app.config.memcached.server, app.config.memcached.options); memcached.on('failure', function(details) { debug('Server: %s went down due to %s', details.server, details.messages.join(' ')); }); memcached.on('reconnecting', function(details) { debug('Total downtime caused by server %s: %sms', details.server, details.totalDownTime); }); memcached.get(handshakeData.cookie['PHPSESSID'], function(err, result) { if (!err && result !== false) { var pipeIndex = result.indexOf('|'), phpData = result.slice(pipeIndex + 1), obj = php.unserialize(phpData); if (handshakeData.node === obj.userLogin) { debug('coockie-accepted: %s, %s', handshakeData.node, obj.userLogin); next(); } else { debug('cookie-revoked; %s, %s', handshakeData.node, obj.userLogin); next(new Error('Cookie is invalid.')); } } else { debug('error: %s', err); next(new Error('Cookie is invalid.')); } memcached.end(); }); } } else { debug('error: No cookie transmitted.'); next(new Error('No cookie transmitted.')); } }; return { authorize: authorize }; }; 
+1
source

I had a similar problem using express.js 4.0 and socket.io 0.9. To solve this in my case, I set up the "authorization" process with my own function, which is a modification of some solution that I found on the network. In this function, you add a session to the data property and access it from the socket handshake property. Look at the code.

I created index.js in the socket folder with this content:

 sio.set('authorization', function(data, accept){ /* NOTE: To detect which session this socket is associated with, * we need to parse the cookies. */ if (!data.headers.cookie) { return accept(null, true); } data.cookie = cookie.parse(data.headers.cookie); data.cookie = parse.signedCookies(data.cookie, sessionContainer.secret); data.sessionID = data.cookie[sessionContainer.key]; sessionContainer.store.get(data.sessionID, function(err, session){ if (err) { return accept('Error in session store.', false); } else if (!session) { return accept('Session not found.', false); } if(!session.username){ return accept('Session not authenticated', true); } data.session = session; return accept(null, true); }); }); 

And then use the data stored in the session:

 sio.sockets.on('connection', function (socket) { var hs = socket.handshake; /* NOTE: At this point, you win. You can use hs.sessionID and * hs.session. */ if(hs.sessionID){ // logged in user console.log('A socket with sessionID '+hs.sessionID+' connected.'); // here you can access whatever you stored in the session console.log('User ' + hs.session.username); socket.emit('news', { hello: 'world' }); socket.on('my other event', function (data) { console.log(data); }); clientSockets[hs.sessionID] = socket; // handle the disconnect socket.on('disconnect', function () { if(clientSockets[hs.sessionID]){ console.log('deleted unused socket ' + hs.sessionID); delete clientSockets[hs.sessionID]; } }); } }); 

You can find the whole project in the following link https://github.com/landreus/dimiblog/blob/master/sockets/index.js

Hope this helps!

0
source

Source: https://habr.com/ru/post/973297/


All Articles