I'm using express 4.0 with module express-session, connect-redis and passport for manage sessions. Everything is ok for login and logout, I can retrieve session etc.
But I've noticed something weird: even when I'm anonymous, if I'm going to redis and type:
$ KEYS *
Redis return an entry 1) "sess:VWdwTjPXkITmqQ77xI8cotlltdrz7S8s" even if nobody is currently connected. When I'm connect, this key is replaced by another corresponding to my session. And when I'm logout, the key changes again by another. When the anonymous user call an URL, my req.sessionID is also set.
In this site https://engineering.linkedin.com/nodejs/blazing-fast-nodejs-10-performance-tips-linkedin-mobile I've read something about create session even for anonymous (7. Go session-free) and I think it's related.
I add the middlewhere in the main app.js file with something like:
var
passport = require('passport'),
User = require('../models/user'),
LocalStrategy = require('passport-local').Strategy,
session = require('express-session'),
RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore(app.locals.services.session.config),
secret: 'mysecretstring'
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
I have the problem even if I start from a fresh server and if I try to GET the homepage where I'm doing nothing:
index: function (req, res) {
res.render('home/index');
}
Even in this case, a new key is created in my redis.
Note:
If I remove both lines, no key are created.
app.use(passport.initialize());
app.use(passport.session());
So, my question is: How to avoid a key creation in Redis for anonymous users ? (and, is it a good idea to not store a session for anonymous ?).
Thanks !
If you don't want a new session to be created for each request, set saveUninitialized to false in the express-session middleware:
app.use(session({
store : new RedisStore(app.locals.services.session.config),
secret : 'mysecretstring',
saveUninitialized : false,
}));
Related
I am trying to access my session token from other routes after setting it in a route. I am currently unsuccessful. Following the relevant code of the three files.
server.js: It calls the routes thermostats, login and also sets session token.
var session = require('express-session');
var app = express();
app.use(session({secret: 'keyboard cat',cookie: { secure: true }}))
var router = express.Router();
var thermostats = require('./api/routes/thermostats')(router, app, session);
require('./api/routes/login')(router, app, session, thermostats);
login.js: When the user goes to localhost:3000/login/, the login token needs to be saved in the session
module.exports = function(router,app, session, thermostats){
router.get('/login/', function(req, res) {
list(req, res) //response of this function has session which needs to be saved.
console.log(res.session)
app.use(session(res.session)) //trying to save the res.session as session token
});
}
thermostat.js: Needs to access the session token before can display any information.
module.exports = function(router,app){
router.get('/thermostats/', function(req, res) {
console.log(req.session) //Set to default/null values and not the updated session values
});
}
It might be something small but I cannot figure out the issue. I would appreciate any help.
Thank you
Express-session should automatically save the session, based on the configuration.
Looking at the 'resave' config option in the express-session docs:
resave
Forces the session to be saved back to the session store, even if the session was never modified during the request. Depending
on your store this may be necessary, but it can also create race
conditions where a client makes two parallel requests to your server
and changes made to the session in one request may get overwritten
when the other request ends, even if it made no changes (this behavior
also depends on what store you're using).
This is by default, true, so it should already start working without you needing to add app.use(session(res.session).
Edit: You will be able to save to the session by adding fields to the req.session object:
router.get('/login/', function(req, res) {
getDataFromExternalApi(req, function(err, apiResponse) {
var data = apiResponse.data;
req.session.data = data;
// if resave option is true, this should automatically save to the session store after this request is done.
});
});
Generally, you shouldn't be using app.use in your request handlers. Those are generally reserved for setting up the server, as it defines what middleware express uses.
I use express and express-session middleware to build a website, with session enabled. But some url such as /health-check' and/version-checkdo not need session, especially the/health-check`, which will generate a lot of useless session in db(the project use mongodb).I believe there is a good solution to solve the problem.
The following is a snippets of the session:
var session = require('express-session'),
passport = require('passport');
var app = express();
//other middleware.
// Express MongoDB session storage
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret,
cookie: { maxAge: 2628000000 },
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// use passport session
app.use(passport.initialize());
app.use(passport.session());
//...
I suggest to create own middleware function and put there your session middleware as function, but with conditions e.g:
app.use(function(req, res, next){
if(...some condition...){//for example check url
//do something or nothing
next();//very important or request will freeze
} else {//otherwise run session
session({your options})(req, res, next);
}
});
instead your app.use(session())
in one custom middleware you can put any other middleware to add conditions. But when you want to wrap more then one middleware to single custom middleware be careful on 'next'. It can be use only once in middleware (multiple middlewares use use it multiple time). Then you have to create your own callback 'next'.
I have a simple, generic express app. It logs the req.sessionID whenever a certain route is hit. I would expect that refreshing the client page would result in the same sessionID being logged again. This works, if I've imported passport and added the passport middleware after the session middleware. If I either don't use passport at all, or I add passport middleware before the session middleware, then the sessionID is different every time.
I can accept that the ordering of middleware can be finicky. However, my app doesn't use passport at all, so I can't fathom why my app doesn't work if I don't require passport. Should passport be necessary for sessions to work?
//generic express initialization
var http = require('http');
var express = require('express');
var cookieParser = require('cookie-parser');
var passport = require('passport');
var session = require('express-session');
var app = express();
var server = http.createServer(app);
var sessionMiddleware = session({resave: false, saveUninitialized: false, secret: 'hunter2'});
app.use(cookieParser());
//This works:
app.use(sessionMiddleware);
app.use(passport.initialize());
//This doesn't:
app.use(passport.initialize());
app.use(sessionMiddleware);
Switch to resave: true, saveUninitialized: true
Unmodified sessions were not being saved, thus resulting in repeatedly generating new session IDs. Passport, however, was presumably doing some initialization on the session, meaning that the session was no longer unmodified.
Thanks to #Dodekeract and #Swaraj Giri for figuring the issue in their comments!
I set up session management in my node js/ express js website successfully. I stores session data in mongo db. I want the session to be valid for the users who log in for a couple of weeks. The code is as follows:
var cookieParser = require('cookie-parser');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
app.use(cookieParser());
app.use(session({
store: new MongoStore({ mongoose_connection: db }),
secret: 'cookie_secret',
cookie: { maxAge: null }
}));
It works fine for normal users, but my problem is with web crawlers such as google bots and facebook bots. I still want them to crawl my website but I don't want their sessions to be stored in my mongo db. It's taking up lots of space and storage is increasing daily which costs me money.
How to selectively choose which sessions to be stored in the db. I can check for req.headers['user-agent'], but where to use it in my code? How to tell express-session not to store session sometimes?
You can use the session middleware conditionally, based on the User-Agent header. A simple example:
var sessionMiddleware = require('express-session')({
...configuration here...
});
app.use(function(req, res, next) {
var ua = req.get('user-agent');
// If the User-Agent header contains the string "Googlebot",
// skip the session middleware.
if (/Googlebot/.test(ua)) {
req.session = {}; // perhaps a bit too simple?
return next();
}
return sessionMiddleware(req, res, next);
});
It would depend on your actual use of req.session if the code above works, or if you need to mock req.session a bit better (for instance, if you use any of the req.session methods in your code,
you may need to mock those too).
In node.js and express, there are many examples showing how to get session data.
Node.js and Socket.io
Express and Socket.io - Tying it all Together
Socket.io and Session?
As you can see when you visit the 3rd link, it's a link to StackOverflow. There was a good answer, but as pointed out in those comments by #UpTheCreek, connect no longer has the parseCookie method. I have just run into this problem as well. All of the tutorials I have found uses connect's parseCookie method which now doesn't exist. So I asked him how we can get the session data and he said he doesn't know the best approach so I thought I'd post the question here. When using express#3.0.0rc4, socket.io, and redis, how can we get session data and use that to authorize the user? I've been able to use require('connect').utils.parseSignedCookie;, but when I do that, I always get a warning/error when handshaking,
warn - handshake error Error
and from what I've read it sounds like that isn't a permanent solution anyways.
UPDATE
Ok I got session.socket.io working on my server. And as I suspected, I got stuck at the point of authorizing. I think I might be going about this the wrong way, so feel free to correct me. In my Redis database, I will have user's information. The first time that they login, I want to update their cookie so it contains their user information. Then the next time they come back to the site, I want to check if they have a cookie and if the user information is there. If it is not there, I want to send them to the login screen. At the login screen, when a user submits information, it would test that information against the Redis database, and if it matches, it would update the cookie with user information. My questions are these:
1) How can I update/change a cookie through RedisStore?
2) It looks like session data is saved only in cookies. How can I keep track of user information from page to page if someone has cookies turned off?
Here is my applicable code:
//...hiding unapplicable code...
var redis = require('socket.io/node_modules/redis');
var client = redis.createClient();
var RedisStore = require('connect-redis')(express);
var redis_store = new RedisStore();
var cookieParser = express.cookieParser('secret');
app.configure(function(){
//...hiding unapplicable code...
app.use(cookieParser);
app.use(express.session({secret: 'secret', store: redis_store}));
});
//...hiding code that starts the server and socket.io
var SessionSockets = require('session.socket.io');
var ssockets = new SessionSockets(io, redis_store, cookieParser);
io.configure(function(){
io.set('authorization', function(handshake, callback){
if(handshake.headers.cookie){
//var cookie = parseCookie(handshake.headers.cookie);
//if(cookie.user){
// handshake.user = cookie.user;
//}
}
callback(null, true);
});
});
ssockets.on('connection', function(err, socket, session){ ... });
Have a look at socket.io's wiki. Especially the parts Configuring Socket.IO and Authorization and handshaking.
It shows how to use socket.io with a RedisStore and gives two different authorization methods.
More information about connecting express v3, redis and socket.io
connect issue#588
socket.io and express 3
session.socket.io module
socket.io-express library
After switching to session.socket.io for a while I ran into a few problems due to the asynchronous nature of the module when loading the session information. So I ended up creating my own module called session.io. It is used like this:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
//Setup cookie and session handlers
//Note: for sessionStore you can use any sessionStore module that has the .load() function
//but I personally use the module 'sessionstore' to handle my sessionStores.
var cookieParser = express.cookieParser('secret');
var sessionStore = require('sessionstore').createSessionStore();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
//...truncate...//
app.use(cookieParser);
//make sure to use the same secret as you specified in your cookieParser
app.use(express.session({secret: 'secret', store: sessionStore}));
app.use(app.router);
});
app.get('/', function(req, res){
res.send('<script src="/socket.io/socket.io.js"></script><script>io.connect();</script>Connected');
});
server.listen(app.get('port'), function(){
console.log('Listening on port ' + app.get('port'));
});
var io = require('socket.io').listen(server);
io.configure(function(){
//use session.io to get our session data
io.set('authorization', require('session.io')(cookieParser, sessionStore));
});
io.on('connection', function(socket){
//we now have access to our session data like so
var session = socket.handshake.session;
console.log(session);
});
Your questions:
How can I update/change a cookie through RedisStore?
It looks like session data is saved only in cookies. How can I keep track of user information from page to page if someone has cookies turned off?
Cookies / Sessions / RedisStore Thoughts:
Typically, you have exactly one cookie, which is the session id
All user-state is stored on the server in a "session" which can be found via the session id
You can use Redis as your back-end storage for your session data.
Redis will allow you to keep session state, even when your server is restarted (good thing)
You can store a mountain of data in your session (req.session.key = value)
All data stored in the session will be persistant until the user logs out, or their session expires
Example node.js Code:
var app = express.createServer(
express.static(__dirname + '/public', { maxAge: 31557600000 }),
express.cookieParser(),
express.session({ secret: 'secret', store: new RedisStore({
host: 'myredishost',
port: 'port',
pass: 'myredispass',
db: 'dbname',
}, cookie: { maxAge: 600000 })})
);
Session and Cookie Thoughts:
Your second issue us about sessions without cookies. This is possible.
You, basically, put the session id on the url of every request you send to the server.
I strongly believe that most people allow cookies.
If this is a requirement, google: "session without cookies"
Session data is available with:
req.session