¿Cómo puedo compartir una sesión con Socket.io 1.0 y Express 4.x? Utilizo Redis Store, pero creo que no debería importar. Sé que tengo que usar un middleware para ver las cookies y recuperar la sesión, pero no sé cómo. Busqué pero no pude encontrar ninguno que funcionara
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'));
}
});
{ path: '/', _expires: null, originalMaxAge: null, httpOnly: true, secure: true } }
Pero si imprimo la sesión en mis rutas, obtengo todas las variables de sesión que configuré (nombre de usuario, identificación, etc.)Hace solo un mes y medio me enfrenté al mismo problema y luego escribí una extensa publicación de blog sobre este tema que va junto con una aplicación de demostración completamente funcional alojada en GitHub. La solución se basa en módulos de nodo express-session , cookie-parser y connect-redis para atar todo. Le permite acceder y modificar sesiones desde el contexto REST y Sockets, lo cual es bastante útil.
Las dos partes cruciales son la configuración del middleware:
app.use(cookieParser(config.sessionSecret)); app.use(session({ store: redisStore, key: config.sessionCookieKey, secret: config.sessionSecret, resave: true, saveUninitialized: true }));
... y configuración del servidor 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(); }); }); });
Van junto con un módulo sessionService simple que hice que le permite hacer algunas operaciones básicas con sesiones y ese código se ve así:
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); } };
Dado que hay más código para todo esto (como inicializar módulos, trabajar con sockets y llamadas REST tanto en el lado del cliente como en el del servidor), no pegaré todo el código aquí, puedes verlo en GitHub. y puedes hacer lo que quieras con él.
fuente
express-socket.io-session
es una solución lista para su problema. Normalmente, la sesión creada en el extremo de socket.io tiene un sid diferente a los creados en express.js
Antes de conocer ese hecho, cuando estaba trabajando en ello para encontrar la solución, encontré algo un poco extraño. Las sesiones creadas a partir de la instancia de express.js eran accesibles en el extremo de socket.io, pero no era posible lo mismo para lo contrario. Y pronto me di cuenta de que tengo que trabajar a través de la gestión de Sid para resolver ese problema. Pero, ya había un paquete escrito para abordar ese problema. Está bien documentado y hace el trabajo. Espero eso ayude
fuente
Usando la respuesta de Bradley Lederholz, así es como lo hice funcionar para mí. Consulte la respuesta de Bradley Lederholz para obtener más explicaciones.
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);
fuente
Lo he resuelto un poco, pero no es perfecto. No admite cookies firmadas, etc. Utilicé la función getcookie de express-session . La función modificada es la siguiente:
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);
fuente
Ahora, la respuesta original aceptada tampoco me funciona. Al igual que @ Rahil051, utilicé el módulo express-socket.io-session y todavía funciona. Este módulo utiliza un analizador de cookies para analizar la identificación de la sesión antes de ingresar al middleware de sesión rápida. Creo que es silmiar para @pootzko, @Mustafa y la respuesta de @ Kosar.
Estoy usando estos módulos:
"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" }
echa un vistazo a los datos en 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.stringify(socket.handshake, null, 2)); debug('check headers %s', JSON.stringify(socket.request.headers)); debug('check socket.id %s', JSON.stringify(socket.id)); next(); }); io.sockets.on('connection', (socket) => { connections.push(socket); }); };
fuente