2012-08-29 12 views
17

Estoy tratando de hacer una aplicación de chat basada en Node.js. Me gustaría forzar al servidor websocket (biblioteca ws) a usar el sistema de sesión ExpressJS. Lamentablemente, me he quedado atrapado. Los hashes de MemoryStore utilizados para obtener datos de las sesiones son diferentes a los ID de sesión en las cookies. ¿Alguien podría explicarme qué estoy haciendo mal?ExpressJS & Websocket y sesión compartida

WebSocket código de servidor parte:

module.exports = function(server, clients, express, store) { 
    server.on('connection', function(websocket) { 
    var username; 

    function broadcast(msg, from) {...} 

    function handleMessage(msg) {...} 

    express.cookieParser()(websocket.upgradeReq, null, function(err) { 
     var sessionID = websocket.upgradeReq.cookies['sid']; 

      //I see same value in Firebug 
     console.log(sessionID); 

      //Shows all hashes in store 
      //They're shorter than sessionID! Why? 
     for(var i in store.sessions) 
      console.log(i); 

     store.get(sessionID, function(err, session) { 
       websocket.on('message', handleMessage); 

       //other code - won't be executed until sessionID in store 

       websocket.on('close', function() {...}); 
     }); 
    }); 
}); 
} 

almacén de objetos definición: configuración

var store = new express.session.MemoryStore({ 
    reapInterval: 60000 * 10 
}); 

aplicación:

app.configure(function() { 
    app.use(express.static(app.get("staticPath"))); 
    app.use(express.bodyParser()); 
    app.use(express.cookieParser()); 

    app.use(express.session({ 
     store: store, 
     secret: "dO_ob", 
     key: "sid" 
    })); 
}); 

Parte de código principal:

var app = express(); 
var httpServer = http.createServer(app); 
var websocketServer = new websocket.Server({server: httpServer}); 
httpServer.listen(80); 

Ejemplo de salida de depuración:

- websocket.upgradeReq.headers.cookie "sid=s%3A64a%2F6DZ4Mab8H5Q9MTKujmcw.U8PJJIR%2BOgONY57mZ1KtSPx6XSfcn%2FQPZ%2FfkGwELkmM" 
- websocket.upgradeReq.cookies["sid"] "s:64a/6DZ4Mab8H5Q9MTKujmcw.U8PJJIR+OgONY57mZ1KtSPx6XSfcn/QPZ/fkGwELkmM" 
- i "64a/6DZ4Mab8H5Q9MTKujmcw" 
+1

simple, feo solución ayuda a: Id.sesión = sessionID.match (/: [a-zA-Z0-9/+] + \ ./) [0]. rebanada (1, -1), pero me gustaría resolver este problema. – skorczan

+0

Gracias por la solución, me ayudó :) ¿Alguna vez encontró una solución adecuada para esto? – Tim

Respuesta

16

yo era capaz de conseguir este trabajo. Creo que debes especificar el secreto en cookieParser en lugar de la tienda de sesiones.

ejemplo de mi aplicación:

var app = express(); 
var RedisStore = require('connect-redis')(express); 
var sessionStore = new RedisStore(); 
var cookieParser = express.cookieParser('some secret'); 

app.use(cookieParser); 
app.use(express.session({store: sessionStore})); 


wss.on('connection', function(rawSocket) { 

    cookieParser(rawSocket.upgradeReq, null, function(err) { 
    var sessionID = rawSocket.upgradeReq.signedCookies['connect.sid']; 
    sessionStore.get(sessionID, function(err, sess) { 
     console.log(sess); 
    }); 
    }); 

}); 
14

he encontrado que esto funciona para mí. Sin embargo, no estoy seguro de que sea la mejor manera de hacerlo. Primero, inicialice su aplicación expresa:

// whatever your express app is using here... 
var session = require("express-session"); 
var sessionParser = session({ 
    store: session_store, 
    cookie: {secure: true, maxAge: null, httpOnly: true} 
}); 
app.use(sessionParser); 

Ahora, llame explícitamente al middleware de sesión desde la conexión WS. Si está utilizando el módulo express-session, el middleware analizará las cookies por sí mismo. De lo contrario, es posible que deba enviarlo a través de su middleware de análisis de cookies primero.

Si está utilizando el módulo websocket:

ws.on("request", function(req){ 
    sessionParser(req.httpRequest, {}, function(){ 
     console.log(req.httpRequest.session); 
     // do stuff with the session here 
    }); 
}); 

Si está utilizando el módulo ws:

ws.on("connection", function(req){ 
    sessionParser(req.upgradeReq, {}, function(){ 
     console.log(req.upgradeReq.session); 
     // do stuff with the session here 
    }); 
}); 

Para su comodidad, aquí es un ejemplo completamente de trabajo, utilizando express, express-session y ws:

var app = require('express')(); 
var server = require("http").createServer(app); 
var sessionParser = require('express-session')({ 
    secret:"secret", 
    resave: true, 
    saveUninitialized: true 
}); 
app.use(sessionParser); 

app.get("*", function(req, res, next) { 
    req.session.working = "yes!"; 
    res.send("<script>var ws = new WebSocket('ws://localhost:3000');</script>"); 
}); 

var ws = new require("ws").Server({server: server}); 
ws.on("connection", function connection(req) { 
    sessionParser(req.upgradeReq, {}, function(){ 
     console.log("New websocket connection:"); 
     var sess = req.upgradeReq.session; 
     console.log("working = " + sess.working); 
    }); 
}); 

server.listen(3000); 
+4

¿Cuidar para explicar el voto a favor? – Azmisov

+0

Un poco tarde para la fiesta, pero su código no se compilará. La línea antes de la última falta un ')' –

+0

@matejkramny Gracias, corregido ahora – Azmisov

0

Actualmente, a continuación se muestra mi solución que funciona bien. Simplemente no sé, son desventajas y seguridad. Solo evito que el servidor escuche si no tiene una sesión. (Share session from express-session to ws)

No he probado completamente esto sin embargo.

var http = require('http'); 
var express = require('express'); 
var expressSession = require('express-session'); 
var router = express.Router(); 
var app = express(); 

const server = http.createServer(app); 

router.get('/', function(req, res, next) { 
    if(req.session.user_id) { 
     // Socket authenticated 
     server.listen(8080, function listening(){}); 
    } 
}); 
0

WS v3.0.0 y superior, ha cambiado el comportamiento por lo que las respuestas dadas no funcionarán de la caja para esas versiones. Para las versiones actuales, la firma del método de conexión es [función (socket, solicitud)] y el socket ya no contiene una referencia a la solicitud.

ws.on(
    'connection', 
    function (socket, req) 
    { 
     sessionParser(
      req, 
      {}, 
      function() 
      { 
       console.log(req.session); 
      } 
     ); 
    } 
); 
0

En la versión 3.2.0 de ws tiene que hacerlo un poco diferente.

Hay un full working example de análisis de sesión exprés en el repositorio ws, específicamente utilizando una nueva característica verifyClient.

un muy breve resumen de uso:

const sessionParser = session({ 
    saveUninitialized: false, 
    secret: '$eCuRiTy', 
    resave: false 
}) 

const server = http.createServer(app) 
const wss = new WebSocket.Server({ 
    verifyClient: (info, done) => { 
    console.log('Parsing session from request...') 
    sessionParser(info.req, {},() => { 
     console.log('Session is parsed!') 
     done(info.req.session.userId) 
    }) 
    }, 
    server 
}) 

wss.on('connection', (ws, req) => { 
    ws.on('message', (message) => { 
    console.log(`WS message ${message} from user ${req.session.userId}`) 
    }) 
})