socket.io y express 4 sesiones

Me gustaría acceder a la sesión express 4 en mi aplicación socket.io. Soy nuevo con Node y tengo algunos problemas para implementar esta funcionalidad.

Encontré un módulo npm que permite el acceso a la sesión express 4: https://www.npmjs.org/package/session.socket.io-express4 o https://github.com/eiriklv/session.socket.io

Si miras el código de mi app.js a continuación, estoy haciendo algo mal en la configuración de la session , sessionStore o cookieParser porque simplemente no puedo hacer que este módulo funcione.

 // init modules var express = require('express'); var helmet = require('helmet'); var fs = require('fs'); var path = require('path'); var favicon = require('static-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var session = require('express-session'); var memoryStore = session.MemoryStore; var app = express(); // set variables var options = { key: fs.readFileSync('./openssl_keys/server_key.pem'), cert: fs.readFileSync('./openssl_keys/server_cert.pem') }; var cookieSecret = "secret phrase"; var sessionStore = new memoryStore(); app.set('env', process.env.NODE_ENV || 'development'); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(favicon()); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser(cookieSecret)); app.use(session({ secret: cookieSecret, cookie: {httpOnly: true, secure: true}, store: sessionStore })); app.use(function(req, res, next){ res.locals.session = req.session; next(); }); app.use(express.static(path.join(__dirname, 'public'))); //routes require('./routes/index')(app); require('./routes/test')(app); // starting http and https servers var http = require('http').createServer(app).listen(8000, function(){ console.log("http server listening on port 8000"); }); var https = require('https').createServer(options, app).listen(8080, function(){ console.log("https server listening on port 8080"); }); // starting socket.io & session handler var serverIO = require('socket.io').listen(https); var SessionSockets = require('session.socket.io-express4'); var io = new SessionSockets(serverIO, sessionStore, cookieParser); io.on('connection', function(err, socket, session){ if(err) throw err; console.log("connected"); //console.log(session); socket.on('clientMessage', function(content) { console.log("received client message") console.log(content); }); }); module.exports = app; 

Intenté múltiples posibilidades como:

  • Desactivando el servidor https .
  • Configuración de un objeto cookieParser con frase secreta (para que “realmente” exporte la frase secreta a io = new SessionSockets(serverIO, sessionStore, cookieParser); )
  • Usar opciones mínimas de cookie

De todos modos estoy un poco perdido con esto, cualquier sugerencia / crítica es bienvenida.


ACTUALIZAR

De acuerdo, entonces, después de numerosos bashs, ¡creo que podría hacer que funcione!

El problema es con la inicialización de cookieParser, que parece ser la correcta:

 var cookieParser = require('cookie-parser'); app.use(cookieParser()); app.use(session({ secret: "secret phrase", cookie: {httpOnly: true, secure: true}, store: sessionStore })); var io = new SessionSockets(serverIO, sessionStore, cookieParser()); 

Tenga en cuenta que si uso var io = new SessionSockets(serverIO, sessionStore, cookieParser); (en lugar de cookieParser() ) entonces no está funcionando. Eso parece ser un problema.

Si uso:

 app.use(cookieParser("secret phrase")); app.use(session({ secret: "secret phrase", cookie: {httpOnly: true, secure: true}, store: sessionStore })); var io = new SessionSockets(serverIO, sessionStore, cookieParser("secret phrase")); 

entonces el módulo se bloquea con el siguiente mensaje de error:

 session.socket.io-express4/session.socket.io.js:41 ake.signedCookies[key] = handshake.signedCookies[key].match(/\:(.*)\./).pop(); ^ TypeError: Cannot call method 'pop' of null 

Pero si uso:

 app.use(cookieParser("secret phrase")); app.use(session({ secret: "secret phrase", cookie: {httpOnly: true, secure: true}, store: sessionStore })); var io = new SessionSockets(serverIO, sessionStore, cookieParser()); 

Entonces todo se ve bien.

Ahora en el documento cookie-parser ( https://github.com/expressjs/cookie-parser ) está diciendo que puede pasar una clave secreta para que se firmen las cookies. Que es algo que me gustaría tener.

¿Podría alguien explicarme la relación con la frase secreta del analizador de cookies y la frase secreta de la sesión? ¿Tienen que ser iguales / diferentes?

Aquí está mi solución para el siguiente entorno:

  • express 4.2.0
  • socket.io 1.1.0
  • cookie-parser 1.0.1
  • cookie-session 1.0.2

Código:

 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); }); }); 

Luego puede acceder a la sesión desde el handshake del zócalo:

 io.on('connection', function (socket) { console.log("Session: ", socket.handshake.session); }); 

Para las personas que se preguntan cómo / por qué esto funciona:

  • Enviamos la solicitud de handshake través del analizador de cookies para que las cookies estén disponibles
  • Luego enviamos el handshake través del middleware de sesión como si fuera una solicitud normal
  • El middleware conecta la session a la solicitud
  • Usamos el handshake porque, a todos los efectos, es una solicitud normal, y el analizador y el middleware de sesión pueden manejarlo correctamente. Es por eso que debe acceder a la session través del handshake

Con el nuevo middleware de sesión exprés, todo lo que tiene que hacer es agregar el middleware IO:

 io.use(function(socket, next) { session(socket.handshake, {}, next); }); 

Un ejemplo completo se vería así:

 var io = require('socket.io')(server); var Session = require('express-session'), SessionStore = require('session-file-store')(Session); session = Session({ store: new SessionStore({ path: './tmp/sessions' }), secret: 'pass', resave: true, saveUninitialized: true }); io.use(function(socket, next) { session(socket.handshake, {}, next); }); io.on('connection', function(socket){ console.log('a user connected'); socket.emit('chat message', "UserID: " + socket.handshake.session.uid); }); 

Creé un paquete super mini npm socket.io-express-session que funciona como he explicado anteriormente.

Esto funcionó para mí con

  • express 4.9.0
  • express.io 1.1.13
  • connect-redis 2.1.0
  • sesión expresa 1.8.2

Lo que quería era compartir sesiones con una API frontend y back-end a través de redis. Máquinas separadas, compartiendo la misma base de datos. Se crean sesiones y los usuarios inician sesión cuando abren la página en la interfaz, luego la API busca las solicitudes de los usuarios que inician sesión.

 var cookieParser = require('cookie-parser')(); var session = require('express-session'); var RedisStore = require('connect-redis')(session); var db = require('./db')(config); var sessionStore = session( { store: new RedisStore({ client: db }), secret: SECRET, cookie: { secure: false } } ); app.use(cookieParser); app.use(sessionStore); // attach sessions to pure websocket requests app.io.use(function(req, next) { var res = {}; cookieParser(req, res, function(err) { if (err) { return next(err); } sessionStore(req, res, next); }); }); 

Nota : configuro cookie.secure en falso para que pueda realizar pruebas sin https localmente.

Esto puede funcionar express 4 / socket.io 1.X Cogí este código desde https://github.com/turbonetix/bus.io/blob/master/demo/chat/app.js

 io.use(function (socket, next) { var handshake = socket.handshake; if (handshake.headers.cookie) { cookieParser()(handshake, {}, function (err) { handshake.sessionID = connect.utils.parseSignedCookie(handshake.cookies[config.session.key], config.session.secret); handshake.sessionStore = config.session.store; handshake.sessionStore.get(handshake.sessionID, function (err, data) { if (err) return next(err); if (!data) return next(new Error('Invalid Session')); handshake.session = new session.Session(handshake, data); next(); }); }); } else { next(new Error('Missing Cookies')); } }); 

express 4.13.4 / socket.io 1.4.5

Miro todas las soluciones y módulos, pero no todos funcionan en mi aplicación. Finaly –

 app.use(session({ secret: COOKIE_SECRET, resave: true, saveUninitialized: true, store:sessionStore, cookie: { domain: 'localhost',secure: false } })); io.use(function(socket, next) { session({ secret: COOKIE_SECRET, resave: true, saveUninitialized: true, store:sessionStore, cookie: { domain: 'localhost',secure: false } })(socket.handshake, {}, next); }); 

trabajando como un encanto.

me costó encontrar la solución adecuada. Esto es lo que funciona para mí:

 /* Just to see, before my code : var sessionStore = new mongoStore({ db: db.connection.db, collection: config.sessionCollection }); app.use(session({ secret: config.sessionSecret, store: sessionStore })); */ io.use(function(socket, next) { var handshake = socket.handshake; if (handshake.headers.cookie) { cookieParser(config.sessionSecret)(handshake, {}, function(err) { handshake.sessionID = handshake.signedCookies['connect.sid']; // <- 'connect.sid' > your key could be different, but this is the default handshake.sessionStore = sessionStore; handshake.sessionStore.get(handshake.sessionID, function(err, data) { if (err) return next(err); if (!data) return next(new Error('Invalid Session')); handshake.session = new session.Session(handshake, data); next(); }); }); } else { next(new Error('Missing Cookies')); } }); 

express 4.2.0 / socket.io 1.0.6

express-socket.io-session es una solución preparada para su problema. Normalmente, la sesión creada en socket.io end tiene diferentes sid que los creados en express.js

Antes de saber ese hecho, cuando estaba trabajando para encontrar la solución, encontré algo un poco raro. Las sesiones creadas desde la instancia de express.js eran accesibles en el socket.io final, pero no era posible lo mismo por el contrario. Y pronto llegué a saber que tenía que trabajar para administrar el 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