Search code examples
javascriptnode.jsredispassport.jsmiddleware

Session Node.js + Passport.js + Redis, Store session by user.id


When a user logs in a session is created for him, but if he were to go to another computer and login a 2nd session would be created for his account. I would like to make it so that a user could not have more then one valid session. Is there anyway to store sessions in redis by user.steamId so that his first session becomes invalid?

Any help would be great thanks!

app.js

    var express = require('express'),
    http = require('http');
var app = express();
var cookie = require('cookie');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var redis = require('redis');
var client = redis.createClient();
var session = require('express-session');
var redisStore = require('connect-redis')(session);
io.set('transports', ['websocket']);

var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
const fs = require('fs');
require('./config/passport')(passport);


var sessionMiddleware = session({
    store:new redisStore({host:'localhost',port:6379,client:client}),
    secret:'secretTextchange',
    saveUninitialized:false,
    resave:false
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));

app.use(sessionMiddleware);
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

require('./routes/routes')(app,passport,client);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});
io.use(function(socket, next) {
    sessionMiddleware(socket.request, {}, next);
});
io.sockets.on('connection', function (socket) {
        console.log("verified");
        socket.on('message',function(msg){
            io.sockets.emit('rmessage', {
                name:socket.request.session.passport.user.name,
                avatarUrl:socket.request.session.passport.user.avatarUrl,
                message:msg
            });
        });

});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});
server.listen(3000);

module.exports = app;

passport.js

var OpenIDStrategy = require('passport-openid').Strategy;
var auth = require('./auth');
var steam = require('./steam');
var s = new steam({
    apiKey: auth.Steam.apiKey,
    format:'json'
})
module.exports = function(passport){

    passport.serializeUser(function(user, done) {

        done(null, user);
    });

    passport.deserializeUser(function(user, done) {


        done(null,user);
    });

    var SteamStrategy = new OpenIDStrategy({
            // OpenID provider configuration
            providerURL: auth.Steam.providerUrl,
            stateless: auth.Steam.stateless,
            // How the OpenID provider should return the client to us
            returnURL: auth.Steam.returnUrl,
            realm: auth.Steam.realm,
        },

        function(identifier, done) {

            process.nextTick(function () {
                console.log("passport-"+identifier);

                s.getPlayerSummaries({
                    steamids:identifier.match(/\d+$/)[0],
                    callback:function(err,data){
                        var user = {
                            steamid:identifier.match(/\d+$/)[0],
                            avatarUrl: data.response.players[0].avatar,
                            name:data.response.players[0].personaname
                        };
                        return done(null, user);
                    }
                });
                // In case of an error, we invoke done(err).
                // If we cannot find or don't like the login attempt, we invoke
                // done(null, false).
                // If everything went fine, we invoke done(null, user).
            });
        });

    passport.use(SteamStrategy);

}

routes.js

module.exports = function(app,passport,client){

    app.get('/', function (req,res) {
        res.render('index.ejs',{
                                user: req.user,
                               title:"yo"});
    });

    app.get('/auth',passport.authenticate('openid'));

    app.get('/auth/return',passport.authenticate('openid'),function(req,res){

        if (req.user) {
            res.redirect('/');
        } else {
            res.redirect('/');
        }
    });
}

Solution

  • Could you use this: https://www.npmjs.com/package/redis-sessions ?

    There's a method called soid which gets all sessions of a single id. You could query user's id as they log in. Then get all the sessions from that id. If soid returns empty you can safely assume the user had no sessions. If it returns with things inside it, then the user has sessions.

    This is my best attempt right now.

    Good luck.