socket.io session does not update when req.session

2020-07-22 17:45发布

问题:

I am currently working on a basic app where a user needs to authenticate (with passportJS) and then send a message to my server with socket.io. Here is the nodeJS code:

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressSession = require('express-session');
var mongoose = require('mongoose');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

var routes = require('./routes/index');
var api = require('./api/index');
var auth = require('./routes/auth');

var session = expressSession({secret: 'mySecret', resave: true, saveUninitialized: true});
var port = normalizePort(process.env.PORT || '3000');

var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var sharedsession = require('express-socket.io-session');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.set('port', port);

//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session);
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/bower_components', express.static(path.join(__dirname, 'bower_components')));

app.use('/', routes);
app.use('/api', api);
app.use('/auth', auth);

// passport config
var User = require('./models/user');
passport.use(new LocalStrategy({
    usernameField: 'email'
}, User.authenticate()));
passport.use(require('./strategies/facebook'));
passport.use(require('./strategies/google'));
passport.serializeUser(function(user, done) {
    done(null, { id: user._id });
});
passport.deserializeUser(function(obj, done) {
    done(null, obj);
});

io.use(sharedsession(session, {
    autoSave:true
}));

io.on('connection', function(socket) {
    console.log('user connected');
    console.log(socket.handshake.session);
    socket.on('message-new', function(data) {
        console.log('receiving message to create');
        console.log(socket.handshake.session);
    });

    socket.on('disconnect', function() {
        console.log('user disconnected');
    });
});

server.listen(port);

So as you can see I use express-socket.io-session to be able to access the session in my socket and it is supposed to be the same than req.session. So at first when a user is connected to the socket.io (but not authenticated), his socket.handshake.session is equal to req.session so:

Session {
cookie: 
{ path: '/',
 _expires: null,
 originalMaxAge: null,
 httpOnly: true } }

once he authenticates, req.session becomes:

cookie: 
 { path: '/',
 _expires: null,
 originalMaxAge: null,
 httpOnly: true },
passport: { user: { id: 56a13e58150f42fc29b44b7a } } }

but when I emit a message-new from the client and that it displays socket.handshake.session, it is still equals to

Session {
cookie: 
{ path: '/',
 _expires: null,
 originalMaxAge: null,
 httpOnly: true } }

So the socket's session was not updated when req.session was. How can I change this behavior? I need to be able to know in my socket if the user is connected or not...

回答1:

Inside your event listener 'new message' you can tell the session to reload, the docs don't explicitly say this, but it shares some of the same methods with the express-session

Inside your event listener you can tell session to reload

socket.handshake.session.reload(function(err) {
    // this will give you the update session info
}

With the 'express-session' you can use the same method as in the docs