socket.io et session?

95

J'utilise un framework express. Je souhaite accéder aux données de session depuis socket.io. J'ai essayé express dynamicHelpers avec les données client.listener.server.dynamicViewHelpers, mais je ne peux pas obtenir les données de session. Existe-t-il un moyen simple de le faire? S'il vous plaît voir le code

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
la source
5
Ou peut utiliser ce très bel
Fabiano Soriani
3
@FabianoPS - ne fonctionnera plus - connect ne fournit plus la méthode parseCookie sur laquelle cela repose.
UpTheCreek
1
@UpTheCreek - Puisque connect n'utilise plus la méthode parseCookie, comment est-ce possible?
Aust
@Aust - Bonne question, je ne sais pas quelle est la meilleure approche actuellement. C'est vraiment un désordre IMO. Malheureusement, la plupart des discussions sur la solution de contournement sont également axées sur socket.io (tout le monde n'utilise pas socket.io!). Il existe maintenant une fonction parseSignedCookie, mais elle est également privée, donc elle risque également d'interrompre les modifications.
UpTheCreek
2
Pour les versions plus récentes de Socket.IO (1.x) et Express (4.x), vérifiez cette question SO: stackoverflow.com/questions/25532692
...

Réponses:

68

Cela ne fonctionnera pas pour les sockets passant par le transport flashsocket (cela n'envoie pas au serveur les cookies nécessaires) mais cela fonctionne de manière fiable pour tout le reste. Je viens de désactiver le transport flashsocket dans mon code.

Pour le faire fonctionner, du côté express / connect, je définis explicitement le magasin de session afin de pouvoir l'utiliser dans le socket:

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

Ensuite, dans mon code de socket, j'inclus le framework de connexion afin que je puisse utiliser son analyse de cookie pour récupérer le connect.sid des cookies. Je recherche ensuite la session dans le magasin de sessions qui a ce connect.sid comme ceci:

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

Vous pouvez ensuite utiliser la session selon vos besoins.

pr0zac
la source
3
Il semble que socket_client.request a été supprimé dans les dernières versions de socket.io-node
Art
6
Méfiez-vous ... il existe de nouvelles conventions pour faire cela maintenant ... Je suggérerais d'utiliser plutôt l'authentification Socket.IO. Voir le message de @Jeffer
BMiner
2
Malheureusement, cela ne fonctionnera plus - parseCookie ne fait plus partie des utilitaires de connexion. Apparemment, cela n'a jamais fait partie de l'API publique. Il y a une alternative désordonnée - parseSignedCookie, mais c'est aussi privé, donc je suppose qu'il risque de disparaître aussi ..
UpTheCreek
Maintenant que j'y pense ... pourquoi ne pas simplement définir le magasin pour les cookies et le magasin pour la socket sur le même magasin?
James
34

La solution de module Socket.IO-sessions expose l'application aux attaques XSS en exposant l'ID de session au niveau du client (script).

Vérifiez plutôt cette solution (pour Socket.IO> = v0.7). Consultez la documentation ici .

Jeffer
la source
1
@Jeffer - cette deuxième solution ne fonctionnera plus avec la version actuelle de connect.
UpTheCreek
2
-1 socket.ioest ce qui expose l'ID de session, pas ce module. Ce n'est pas un gros problème puisque l'ID de session est stocké côté client dans un cookie de toute façon ... De plus, ce tutoriel ne fonctionne pas pour la dernière version d'Express.
Aust
1
votre lien de solution redirige simplement vers la socket.iopage github ..?
TJ
8

Je suggère de ne pas réinventer entièrement la roue. Les outils dont vous avez besoin sont déjà un package npm.Je pense que c'est ce dont vous avez besoin: session.socket.io Je l'utilise ces jours-ci et ce sera très utile je suppose !! Lier la session express à la couche socket.io aura tellement d'avantages!

Francesco
la source
6
Voici un module mis à jour qui prend en charge socket.io-express-sessions pour socket.io> = 1.0 github.com/xpepermint/socket.io-express-session
blnc
4

Edit: Après avoir essayé des modules qui ne fonctionnaient pas, j'ai en fait écrit ma propre bibliothèque pour ce faire. Prise sans vergogne: allez le vérifier sur https://github.com/aviddiviner/Socket.IO-sessions . Je laisserai mon ancien message ci-dessous à des fins historiques:


Je suis tout à fait ce travail d'une manière ordonnée sans avoir à contourner le flashsocket de transport selon pr0zac la solution « ci - dessus. J'utilise également express avec Socket.IO. Voici comment.

Commencez par transmettre l'ID de session à la vue:

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

Ensuite, dans votre vue, liez-le avec Socket.IO côté client:

<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'});"/>

Ensuite, dans votre écouteur Socket.IO côté serveur, récupérez-le et lisez / écrivez les données de session:

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

Dans mon cas, mon session_storeest Redis, en utilisant la redis-connectbibliothèque.

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

J'espère que cela aide quelqu'un qui trouve ce message lors d'une recherche sur Google (comme je l'ai fait;)

Dave
la source
8
Mettre votre identifiant de session dans le html client n'est pas une bonne idée du point de vue de la sécurité ...
UpTheCreek
4
Pourquoi mettre l'identifiant de session dans le HTML est une si mauvaise idée alors que l'identifiant de session est déjà stocké dans un cookie local?
Gavin
3
Parce que les cookies ne sont pas accessibles à partir de JavaScript lorsqu'ils sont définis comme cookie HttpOnly. En mettant session.sid dans le HTML, vous donnez à l'attaquant tout ce dont il a besoin dans le DOM.
rochal
3

Voir ceci: Authentification Socket.IO

Je suggérerais de ne rien chercher via client.request...ou client.listener...car cela n'est pas directement attaché à l' clientobjet et pointer toujours vers le dernier utilisateur connecté!

Shripad Krishna
la source
2

Découvrez Socket.IO-connect

Connectez le WebSocket Middleware Wrapper autour du nœud Socket.IO https://github.com/bnoguchi/Socket.IO-connect

Cela vous permettra de pousser la ou les requêtes Socket.IO vers le bas de la pile middleware Express / Connect avant de les traiter avec les gestionnaires d'événements Socket.IO, vous donnant ainsi accès à la session, aux cookies, etc. Cependant, je ne suis pas sûr que cela fonctionne avec tous les transports de Socket.IO.

BMiner
la source
malheureusement , ce module utilise encore v0.6 de socket.io
fent
2

Vous pouvez utiliser express-socket.io-session .

Partagez un middleware de session express basé sur des cookies avec socket.io. Fonctionne avec express> 4.0.0 et socket.io> 1.0.0 et ne sera pas rétrocompatible.

A travaillé pour moi !!

nonybrighto
la source
Hey. Comment utiliseriez-vous les valeurs de session dans le front-end? Je ne peux pas les voir dans les documents npm.
Hari Ram
1

Vous pouvez jeter un œil à ceci: https://github.com/bmeck/session-web-sockets

ou vous pouvez également utiliser:

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

J'espère que cela t'aides.

intellidiot
la source
Je connais session-web-sockets mais je ne veux pas utiliser de bibliothèque pour cela, je cherche une solution simple. J'ai essayé client.listener.server.viewHelpers; mais il a renvoyé ceci: {}
sfs
2
bien que cela semble fonctionner au début, cela conduit à des conditions de course. Je vous suggère de l'éviter complètement.
Shripad Krishna
1

Je ne suis pas sûr de faire les choses correctement. https://github.com/LearnBoost/socket.io/wiki/Authorizing

Avec les données de poignée de main, vous pouvez accéder aux cookies. Et dans les cookies, vous pouvez récupérer connect.sid qui est l'identifiant de session pour chaque client. Et puis utilisez le connect.sid pour obtenir les données de session de la base de données (je suppose que vous utilisez RedisStore)

Tan Nguyen
la source
c'est exactement la voie à suivre, mais vous n'êtes pas cool, vous ne pouvez donc pas obtenir de points de débordement de pile. github.com/tcr/socket.io-session et github.com/functioncallback/session.socket.io J'aime un peu mieux le premier son plus propre. Le second est un peu mieux documenté.
James
@TJ Je suis désolé, mais vous rendez-vous compte que la réponse remonte à 2 ans? Et cela ne fonctionnerait probablement pas maintenant
Tan Nguyen
@TanNguyen Je sais, c'est pourquoi je vous ai notifié afin que vous puissiez mettre à jour la réponse nécessairement que de pointer les gens vers des liens morts
TJ
@TJ Merci pour cela. Malheureusement, je me suis éloigné de socket.io en raison d'un problème de performances il y a 2 ans. Par conséquent, je ne sais pas quelle est la façon actuelle de gérer la session dans socket.io
Tan Nguyen