socket.io y sesión?

95

Estoy usando un marco expreso. Quiero acceder a los datos de la sesión desde socket.io. Intenté expresar dynamicHelpers con datos de client.listener.server.dynamicViewHelpers, pero no puedo obtener datos de sesión. ¿Existe una forma sencilla de hacer esto? Por favor vea el código

app.listen(3000);

var io = require('socket.io');
var io = io.listen(app);

io.on('connection', function(client){
    // I want to use session data here
    client.on('message', function(message){
        // or here
    });
    client.on('disconnect', function(){
        // or here
    }); 
});
sfs
fuente
5
O puede usar esta publicación MUY AGRADABLE: danielbaulig.de/socket-ioexpress
Fabiano Soriani
3
@FabianoPS - ya no funcionará - connect ya no proporciona el método parseCookie en el que se basa.
UpTheCreek
1
@UpTheCreek: dado que connect ya no usa el método parseCookie, ¿cómo puede ser esto posible?
Aust
@Aust - Buena pregunta, no sé cuál es el mejor enfoque ahora. Esto es realmente un lío en mi opinión. Es molesto que la mayoría de las discusiones sobre soluciones también se centren en socket.io (¡no todos usan socket.io!). Ahora hay una función parseSignedCookie, pero también es privada, por lo que también corre el riesgo de romper los cambios.
UpTheCreek
2
Para versiones más nuevas de Socket.IO (1.x) y Express (4.x), consulte esta pregunta SO: stackoverflow.com/questions/25532692/…
pootzko

Respuestas:

68

Esto no funcionará para los sockets que pasan por el transporte flashsocket (no envía al servidor las cookies necesarias) pero funciona de manera confiable para todo lo demás. Acabo de desactivar el transporte flashsocket en mi código.

Para que funcione, en el lado express / connect, defino explícitamente el almacén de sesiones para poder usarlo dentro del socket:

MemoryStore = require('connect/middleware/session/memory'),
var session_store = new MemoryStore();
app.configure(function () {
  app.use(express.session({ store: session_store }));
});

Luego, dentro de mi código de socket, incluyo el marco de conexión para poder usar su análisis de cookies para recuperar el connect.sid de las cookies. Luego busco la sesión en la tienda de sesiones que tiene ese connect.sid así:

var connect = require('connect');
io.on('connection', function(socket_client) {
  var cookie_string = socket_client.request.headers.cookie;
  var parsed_cookies = connect.utils.parseCookie(cookie_string);
  var connect_sid = parsed_cookies['connect.sid'];
  if (connect_sid) {
    session_store.get(connect_sid, function (error, session) {
      //HOORAY NOW YOU'VE GOT THE SESSION OBJECT!!!!
    });
  }
});

A continuación, puede utilizar la sesión según sea necesario.

pr0zac
fuente
3
Parece que socket_client.request se ha eliminado en las últimas versiones de socket.io-node
Art
6
Tenga cuidado ... hay nuevas convenciones para hacer esto ahora ... Sugeriría usar la autenticación Socket.IO en su lugar. Ver publicación de @Jeffer
BMiner
2
Desafortunadamente, esto ya no funcionará: parseCookie ya no es parte de las utilidades de conexión. Al parecer, nunca formó parte de la API pública. Hay una alternativa complicada: parseSignedCookie, pero esto también es privado, así que supongo que también corre el riesgo de desaparecer ..
UpTheCreek
Ahora que estoy pensando en esto ... ¿por qué no configurar la tienda de cookies y la tienda de socket en la misma tienda?
James
34

La solución del módulo de sesiones Socket.IO expone la aplicación a ataques XSS al exponer el ID de sesión a nivel del cliente (scripting).

En su lugar, verifique esta solución (para Socket.IO> = v0.7). Consulte los documentos aquí .

Jeffer
fuente
1
@Jeffer: esa segunda solución ya no funcionará con la versión actual de connect.
UpTheCreek
2
-1 socket.ioes lo que expone el ID de sesión, no ese módulo. Esto no es un gran problema ya que la identificación de la sesión se almacena del lado del cliente en una cookie de todos modos ... Además, ese tutorial no funciona para la última versión de Express.
Aust
1
el enlace de su solución simplemente redirige a la socket.iopágina de github ..?
TJ
8

Sugiero no reinventar completamente la rueda. Las herramientas que necesitas ya son un paquete npm. Creo que esto es lo que necesitas: session.socket.io ¡ Lo estoy usando en estos días y será muy útil, supongo! ¡Vincular la sesión rápida a la capa socket.io tendrá tantas ventajas!

Francesco
fuente
6
Aquí hay un módulo actualizado que admite socket.io-express-sessions para socket.io> = 1.0 github.com/xpepermint/socket.io-express-session
blnc
4

Editar: Después de probar algunos módulos que no funcionaron, en realidad fui y escribí mi propia biblioteca para hacer esto. Enchufe desvergonzado: échale un vistazo a https://github.com/aviddiviner/Socket.IO-sessions . Dejaré mi publicación anterior a continuación con fines históricos:


Obtuve este trabajo bastante bien sin tener que omitir el transporte de flashsocket según pr0zac la solución de anterior. También estoy usando express con Socket.IO. Así es cómo.

Primero, pase el ID de sesión a la vista:

app.get('/', function(req,res){
  res.render('index.ejs', {
    locals: { 
      connect_sid: req.sessionID
      // ...
    }
  });
});

Luego, en su opinión, vincúlelo con el lado del cliente de Socket.IO:

<script>
  var sid = '<%= connect_sid %>';
  var socket = new io.Socket();
  socket.connect();
</script>
<input type="button" value="Ping" onclick="socket.send({sid:sid, msg:'ping'});"/>

Luego, en el oyente Socket.IO del lado del servidor, recójalo y lea / escriba los datos de la sesión:

var socket = io.listen(app);
socket.on('connection', function(client){
  client.on('message', function(message){
    session_store.get(message.sid, function(error, session){
      session.pings = session.pings + 1 || 1;
      client.send("You have made " + session.pings + " pings.");
      session_store.set(message.sid, session);  // Save the session
    });
  });
});

En mi caso, mi session_storees Redis, usando la redis-connectbiblioteca.

var RedisStore = require('connect-redis');
var session_store = new RedisStore;
// ...
app.use(express.session({ store: session_store }));

Espero que esto ayude a alguien que encuentre esta publicación mientras busca en Google (como hice yo;)

Dave
fuente
8
Poner su ID de sesión en el html del cliente no es una buena idea desde una perspectiva de seguridad ...
UpTheCreek
4
¿Por qué es tan mala idea poner la identificación de la sesión en el HTML cuando la identificación de la sesión ya está almacenada en una cookie local?
Gavin
3
Porque no se puede acceder a las cookies desde javascript cuando se configuran como cookies HttpOnly. Al poner session.sid en el HTML, le da al atacante todo lo que necesita en el DOM.
rochal
3

Vea esto: Autenticación Socket.IO

¡Sugeriría no obtener nada a través de client.request...o client.listener...ya que no está directamente adjunto al clientobjeto y siempre apunte al último usuario que inició sesión!

Shripad Krishna
fuente
2

Echa un vistazo a Socket.IO-connect

Conecte el contenedor WebSocket Middleware alrededor del nodo Socket.IO https://github.com/bnoguchi/Socket.IO-connect

Esto le permitirá enviar las solicitudes de Socket.IO por la pila de middleware Express / Connect antes de manejarlas con los controladores de eventos de Socket.IO, lo que le brinda acceso a la sesión, las cookies y más. Aunque, no estoy seguro de que funcione con todos los transportes de Socket.IO.

BMiner
fuente
desafortunadamente, ese módulo todavía usa v0.6 de socket.io
fent de
2

Puede hacer uso de express-socket.io-session .

Comparta un middleware de sesión rápida basado en cookies con socket.io. Funciona con express> 4.0.0 y socket.io> 1.0.0 y no será compatible con versiones anteriores.

¡¡Trabajó para mi!!

nonybrighto
fuente
Oye. ¿Cómo usaría los valores de la sesión en el front-end? No puedo verlos en los documentos npm.
Hari Ram
1

Puedes echarle un vistazo a esto: https://github.com/bmeck/session-web-sockets

o alternativamente puede usar:

io.on('connection', function(client) { 
  var session = client.listener.server.viewHelpers; 
  // use session here 
});

Espero que esto ayude.

intellidiot
fuente
Conozco session-web-sockets pero no quiero usar una biblioteca para esto, estoy buscando una solución simple. Intenté client.listener.server.viewHelpers; pero devolvió esto: {}
sfs
2
aunque esto parece funcionar al principio, conduce a condiciones de carrera. Te sugiero que lo evites por completo.
Shripad Krishna
1

No estoy seguro de estar haciéndolo bien. https://github.com/LearnBoost/socket.io/wiki/Authorizing

Con los datos del protocolo de enlace, puede acceder a las cookies. Y en las cookies, puede tomar connect.sid, que es la identificación de sesión para cada cliente. Y luego use connect.sid para obtener los datos de la sesión de la base de datos (supongo que está usando RedisStore)

Tan Nguyen
fuente
este es exactamente el camino a seguir, pero no es genial, por lo que no puede obtener puntos de desbordamiento de pila. github.com/tcr/socket.io-session y github.com/functioncallback/session.socket.io Me gusta el primero un poco más, es más limpio. El segundo está un poco mejor documentado.
James
@TJ Lo siento, pero ¿te das cuenta de que la respuesta fue hace 2 años? Y probablemente no funcionaría ahora
Tan Nguyen
@TanNguyen Lo sé, es por eso que te notifiqué para que puedas actualizar la respuesta necesariamente en lugar de señalar a las personas los enlaces muertos
TJ
@TJ Gracias por eso. Desafortunadamente, me alejé de socket.io debido a un problema de rendimiento hace 2 años. Por lo tanto, no sé cuál es la forma actual de lidiar con la sesión en socket.io
Tan Nguyen