Comment partager des sessions avec Socket.IO 1.x et Express 4.x?

Comment puis-je partager une session avec Socket.io 1.0 et Express 4.x? J’utilise un Redis Store, mais je crois que cela ne devrait pas avoir d’importance. Je sais que je dois utiliser un middleware pour regarder les cookies et récupérer les sessions, mais je ne sais pas comment. J’ai cherché mais je n’ai pas trouvé de travail

var RedisStore = connectRedis(expressSession); var session = expressSession({ store: new RedisStore({ client: redisClient }), secret: mysecret, saveUninitialized: true, resave: true }); app.use(session); io.use(function(socket, next) { var handshake = socket.handshake; if (handshake.headers.cookie) { var str = handshake.headers.cookie; next(); } else { next(new Error('Missing Cookies')); } }); 

La solution est étonnamment simple. C’est juste pas très bien documenté. Il est également possible d’utiliser le middleware de session express en tant que middleware Socket.IO avec un petit adaptateur comme celui-ci:

 sio.use(function(socket, next) { sessionMiddleware(socket.request, socket.request.res, next); }); 

Voici un exemple complet avec express 4.x, Socket.IO 1.x et Redis:

 var express = require("express"); var Server = require("http").Server; var session = require("express-session"); var RedisStore = require("connect-redis")(session); var app = express(); var server = Server(app); var sio = require("socket.io")(server); var sessionMiddleware = session({ store: new RedisStore({}), // XXX redis server config secret: "keyboard cat", }); sio.use(function(socket, next) { sessionMiddleware(socket.request, socket.request.res, next); }); app.use(sessionMiddleware); app.get("/", function(req, res){ req.session // Session object in a normal request }); sio.sockets.on("connection", function(socket) { socket.request.session // Now it's available from Socket.IO sockets too! Win! }); server.listen(8080); 

Il y a à peine un mois et demi, j’ai traité le même problème et, par la suite, j’ai écrit un article complet sur ce sujet, accompagné d’une application de démonstration entièrement opérationnelle hébergée sur GitHub. La solution repose sur des modules de nœuds express-session , cookie-parser et connect-redis pour tout lier. Il vous permet d’accéder et de modifier des sessions à la fois dans le contexte REST et Sockets, ce qui est très utile.

Les deux parties essentielles sont la configuration du middleware:

 app.use(cookieParser(config.sessionSecret)); app.use(session({ store: redisStore, key: config.sessionCookieKey, secret: config.sessionSecret, resave: true, saveUninitialized: true })); 

… et la configuration du serveur SocketIO:

 ioServer.use(function (socket, next) { var parseCookie = cookieParser(config.sessionSecret); var handshake = socket.request; parseCookie(handshake, null, function (err, data) { sessionService.get(handshake, function (err, session) { if (err) next(new Error(err.message)); if (!session) next(new Error("Not authorized")); handshake.session = session; next(); }); }); }); 

Ils vont de pair avec un simple module sessionService que j’ai fait qui vous permet de faire des opérations de base avec des sessions et ce code ressemble à ceci:

 var config = require('../config'); var redisClient = null; var redisStore = null; var self = module.exports = { initializeRedis: function (client, store) { redisClient = client; redisStore = store; }, getSessionId: function (handshake) { return handshake.signedCookies[config.sessionCookieKey]; }, get: function (handshake, callback) { var sessionId = self.getSessionId(handshake); self.getSessionBySessionID(sessionId, function (err, session) { if (err) callback(err); if (callback != undefined) callback(null, session); }); }, getSessionBySessionID: function (sessionId, callback) { redisStore.load(sessionId, function (err, session) { if (err) callback(err); if (callback != undefined) callback(null, session); }); }, getUserName: function (handshake, callback) { self.get(handshake, function (err, session) { if (err) callback(err); if (session) callback(null, session.userName); else callback(null); }); }, updateSession: function (session, callback) { try { session.reload(function () { session.touch().save(); callback(null, session); }); } catch (err) { callback(err); } }, setSessionProperty: function (session, propertyName, propertyValue, callback) { session[propertyName] = propertyValue; self.updateSession(session, callback); } }; 

Comme il y a plus de code dans tout cela (comme l’initialisation des modules, l’utilisation des sockets et des appels REST du côté client et du côté serveur), je ne collerai pas tout le code ici, vous pouvez le voir sur le GitHub. et vous pouvez faire ce que vous voulez avec.

express-socket.io-session

est une solution prête à l’emploi pour votre problème. Normalement, la session créée à la fin de socket.io a un côté différent de ceux créés dans express.js

Avant de savoir que je travaillais pour trouver la solution, j’ai trouvé quelque chose de bizarre. Les sessions créées à partir de l’instance express.js étaient accessibles à la fin de socket.io, mais il n’en était pas de même pour le contraire. Et bientôt je me suis rendu compte que je devais me débrouiller tout au long de la gestion de Sid pour résoudre ce problème. Mais, il existait déjà un package pour résoudre ce problème. C’est bien documenté et fait le travail. J’espère que cela aide

En utilisant la réponse de Bradley Lederholz, c’est comme ça que je l’ai fait fonctionner pour moi. Veuillez vous reporter à la réponse de Bradley Lederholz pour plus d’explications.

 var app = express(); var server = require('http').createServer(app); var io = require('socket.io'); var cookieParse = require('cookie-parser')(); var passport = require('passport'); var passportInit = passport.initialize(); var passportSession = passport.session(); var session = require('express-session'); var mongoStore = require('connect-mongo')(session); var mongoose = require('mongoose'); var sessionMiddleware = session({ secret: 'some secret', key: 'express.sid', resave: true, httpOnly: true, secure: true, ephemeral: true, saveUninitialized: true, cookie: {}, store:new mongoStore({ mongooseConnection: mongoose.connection, db: 'mydb' }); }); app.use(sessionMiddleware); io = io(server); io.use(function(socket, next){ socket.client.request.originalUrl = socket.client.request.url; cookieParse(socket.client.request, socket.client.request.res, next); }); io.use(function(socket, next){ socket.client.request.originalUrl = socket.client.request.url; sessionMiddleware(socket.client.request, socket.client.request.res, next); }); io.use(function(socket, next){ passportInit(socket.client.request, socket.client.request.res, next); }); io.use(function(socket, next){ passportSession(socket.client.request, socket.client.request.res, next); }); io.on('connection', function(socket){ ... }); ... server.listen(8000); 

Je l’ai un peu résolu, mais ce n’est pas parfait. Ne supporte pas les cookies signés, etc. J’ai utilisé la fonction getcookie de express-session . La fonction modifiée est la suivante:

  io.use(function(socket, next) { var cookie = require("cookie"); var signature = require('cookie-signature'); var debug = function() {}; var deprecate = function() {}; function getcookie(req, name, secret) { var header = req.headers.cookie; var raw; var val; // read from cookie header if (header) { var cookies = cookie.parse(header); raw = cookies[name]; if (raw) { if (raw.substr(0, 2) === 's:') { val = signature.unsign(raw.slice(2), secret); if (val === false) { debug('cookie signature invalid'); val = undefined; } } else { debug('cookie unsigned') } } } // back-compat read from cookieParser() signedCookies data if (!val && req.signedCookies) { val = req.signedCookies[name]; if (val) { deprecate('cookie should be available in req.headers.cookie'); } } // back-compat read from cookieParser() cookies data if (!val && req.cookies) { raw = req.cookies[name]; if (raw) { if (raw.substr(0, 2) === 's:') { val = signature.unsign(raw.slice(2), secret); if (val) { deprecate('cookie should be available in req.headers.cookie'); } if (val === false) { debug('cookie signature invalid'); val = undefined; } } else { debug('cookie unsigned') } } } return val; } var handshake = socket.handshake; if (handshake.headers.cookie) { var req = {}; req.headers = {}; req.headers.cookie = handshake.headers.cookie; var sessionId = getcookie(req, "connect.sid", mysecret); console.log(sessionId); myStore.get(sessionId, function(err, sess) { console.log(err); console.log(sess); if (!sess) { next(new Error("No session")); } else { console.log(sess); socket.session = sess; next(); } }); } else { next(new Error("Not even a cookie found")); } }); // Session backend config var RedisStore = connectRedis(expressSession); var myStore = new RedisStore({ client: redisClient }); var session = expressSession({ store: myStore, secret: mysecret, saveUninitialized: true, resave: true }); app.use(session); 

Maintenant, la réponse originale acceptée ne fonctionne pas non plus pour moi. Identique à @ Rahil051, j’ai utilisé le module express-socket.io-session , et cela fonctionne toujours. Ce module utilise un cookie-parser pour parsingr l’identifiant de session avant d’entrer dans le middleware express-session. Je pense que c’est silmiar à la réponse de @pootzko, @Mustafa et @ Kosar.

J’utilise ces modules:

 "dependencies": { "debug": "^2.6.1", "express": "^4.14.1", "express-session": "^1.15.1", "express-socket.io-session": "^1.3.2 "socket.io": "^1.7.3" } 

consultez les données dans socket.handshake:

 const debug = require('debug')('ws'); const sharedsession = require('express-socket.io-session'); module.exports = (server, session) => { const io = require('socket.io').listen(server); let connections = []; io.use(sharedsession(session, { autoSave: true, })); io.use(function (socket, next) { debug('check handshake %s', JSON.ssortingngify(socket.handshake, null, 2)); debug('check headers %s', JSON.ssortingngify(socket.request.headers)); debug('check socket.id %s', JSON.ssortingngify(socket.id)); next(); }); io.sockets.on('connection', (socket) => { connections.push(socket); }); };