I have a problem for a few days and I could not find a solution, I have searched forums, documentation and nothing.I have a website developed in nodejs, using express-session and passport for session management and user authentication.
My problem is that having two different users connected to my website and do an action simultaneously, the website is loaded but with the session of the last user who has performed the action. In other words, it uses a session for the rest of the users who have performed the action simultaneously.
This is my base configuration of my website
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const exphbs = require('express-handlebars');
const session = require('express-session');
const validator = require('express-validator');
const passport = require('passport');
const flash = require('connect-flash');
const MySQLStore = require('express-mysql-session')(session);
const bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
const helmet = require("helmet");
const { database } = require('./keys');
// Intializations
const app = express();
require('./lib/passport');
// Settings
app.set('port', process.env.PORT || 4000);
app.set('views', path.join(__dirname, 'views'));
app.engine('.hbs', exphbs({
defaultLayout: 'main',
layoutsDir: path.join(app.get('views'), 'layouts'),
partialsDir: path.join(app.get('views'), 'partials'),
extname: '.hbs',
helpers: require('./lib/handlebars')
}))
app.set('view engine', '.hbs');
// Middlewares
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(session({
secret: '1234567789',
key: "namecookie",
resave: true,
saveUninitialized: true,
store: new MySQLStore(database),
cookie: {
secure: false,
maxAge: 150000,
httpOnly: false
}
}));
app.use(function (req, res, next) {
res.locals.session = req.session;
next();
});
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(validator());
// Global variables
app.use((req, res, next) => {
app.locals.message = req.flash('message');
app.locals.success = req.flash('success');
app.locals.user = req.user;
next();
});
// Routes
app.use(require('./routes/index'));
app.use(require('./routes/authentication'));
app.use('/links', require('./routes/links'));
// Public
app.use(express.static(path.join(__dirname, 'public')));
app.use(helmet());
// Starting
app.listen(app.get('port'), () => {
console.log('Server is in port', app.get('port'));
});
Don't EVER use app.locals
for user state or per-request state. That is essentially global to your server and will cause you to mix up which user is the current user as one user's request will overwrite data from another and if they are both in flight at the same time, the data will get mixed up.
Use only properties on req
or res
to keep track of state for the current request (like which user you got from the session).
So, this:
app.locals.user = req.user;
is a problem. Instead, use the data directly from req.user
or use res.locals
and don't ever assign user state or per-request state to any app
property. Remember, there's only one app
object for a given server that ALL users and all requests on that server share.
app.locals
is where you put global state that should apply to all requests on your server. It's not where you put user state or pre-request state.
If you're still confused about app.locals
, read the Express doc on it here. It is for "application-level data" only. Not per-user or per-request data.