web-dev-qa-db-fra.com

socket.io et express 4 sessions

Je souhaite accéder à la session express 4 dans mon application socket.io. Je suis un peu nouveau avec Node et j'ai quelques problèmes pour implémenter cette fonctionnalité.

J'ai trouvé un module npm permettant d'accéder à la session express 4: https://www.npmjs.org/package/session.socket.io-express4 ou https://github.com/eiriklv/ session.socket.io

Si vous examinez mon code app.js ci-dessous, je suis en train de faire quelque chose de mal dans la configuration session, sessionStore ou cookieParser car je ne parviens tout simplement pas à faire fonctionner ce module.

// 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;

J'ai essayé de multiples possibilités comme:

  • Désactivation du serveur https.
  • Configuration d'un objet cookieParser avec une phrase secrète (afin qu'il exporte réellement la phrase secrète vers io = new SessionSockets(serverIO, sessionStore, cookieParser);)
  • Utilisation des options cookie minimales.

Quoi qu'il en soit, je suis un peu perdu avec cela, toutes les suggestions/critiques sont les bienvenues.


UPDATE

Ok, après de nombreux essais, je pense que je pourrais le faire fonctionner!

Le problème vient de l’initialisation de cookieParser qui semble être la bonne solution:

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

Notez que si j'utilise var io = new SessionSockets(serverIO, sessionStore, cookieParser); (au lieu de cookieParser()), cela ne fonctionnera pas. Cela semble être le problème.

Si j'utilise:

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

alors le module se bloque avec le message d'erreur suivant:

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

Mais si j'utilise:

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

Alors tout va bien.

À présent, dans la documentation de l'analyseur de cookies ( https://github.com/expressjs/cookie-parser ), il est indiqué que vous pouvez passer une clé secrète pour obtenir la signature des cookies. Ce qui est quelque chose que j'aimerais avoir.

Quelqu'un pourrait-il m'expliquer la relation entre la phrase secrète cookie-parser et la phrase secrète de la session? Doivent-ils être les mêmes/différents?

10
Bobby Shark

Voici ma solution pour l'environnement suivant:

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

Code:

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

Ensuite, vous pouvez accéder à la session à partir de la poignée de main du socket:

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

Pour ceux qui se demandent comment et pourquoi cela fonctionne:

  • Nous envoyons la demande handshake via l'analyseur de cookies afin que les cookies soient disponibles
  • Ensuite, nous envoyons la variable handshake via le middleware de session comme si c'était une requête normale
  • Le middleware attache session à la demande
  • Nous utilisons handshake car, à toutes fins utiles, il s’agit d’une requête normale, et l’analyseur et l’intergiciel de session peuvent y répondre correctement. C'est pourquoi vous devez accéder à la session à la handshake
20
Sean Adkinson

Avec le nouveau middleware de session express, il vous suffit d'ajouter le middleware IO:

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

Un exemple complet ressemblerait à ceci:

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

J'ai créé un paquet super mini npm socket.io-express-session qui fonctionne comme je l'ai expliqué ci-dessus.

13
xpepermint

Cela a fonctionné pour moi avec

  • express 4.9.0
  • express.io 1.1.13
  • connect-redis 2.1.0
  • express-session 1.8.2

Ce que je voulais, c'était partager des sessions avec une API frontend et backend via redis. Machines séparées, partageant le même DB. Les sessions sont créées et les utilisateurs connectés quand ils ouvrent la page sur le frontend, puis l'API recherche les utilisateurs connectés sur les demandes.

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

Note : Je règle le cookie.secure sur false pour pouvoir tester sans https localement.

2
Eivind

express 4.13.4 / socket.io 1.4.5

Je parcours toutes les solutions et tous les modules, mais ils ne fonctionnent pas tous dans mon application. Enfin -

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

travailler comme un charme.

1
xbtc

Cela peut fonctionner express 4/socket.io 1.X Je me suis emparé de ce formulaire 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'));
 }
});
1
Nathan Romano

express-socket.io-session est une solution toute prête pour votre problème. Normalement, la session créée dans socket.io end a un ID différent de celui créé dans express.js

Avant de le savoir, en cherchant la solution, j'ai trouvé quelque chose d'un peu bizarre. Les sessions créées à partir de l'instance express.js étaient accessibles à la fin du fichier socket.io, mais la même chose n'était pas possible pour le contraire. Et bientôt, j'ai compris que je devais me débrouiller pour gérer ce système afin de résoudre ce problème. Mais, il y avait déjà un paquet écrit pour s'attaquer à ce problème. C'est bien documenté et le travail est fait. J'espère que ça aide

0
Rahil051

j'ai eu du mal à trouver la bonne solution. Voici ce qui fonctionne pour moi:

/*

    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

0
Peter V