On login with in my app, I've noticed that deserializeUser is called 10x. Any ideas why this would be the case.
Any help would be greatly appreciated.
Thanks
i have an idea shaun. the deserialize user function is called for every _asset_ you try and load...that means every js file or css file. to my mind this is sub-optimal...but it's the way it seems to work. to test this...play with the login sample, add a console.log('invoked desrialize') stmt to the deserializeUser function. you'll see it's only only invoked once...becoz the page has no css. now add one or more css files in the head using and re-run the app. voila!
just as a follow-up...it seems to be the case that the deserializeUser function is invoked on _every_ request to the server once a user is logged in. The fact that passport is making the same database call _n_ times (where _n_ is the number of css, js or other asset files in the page), just to load a page is worrying. But the more interesting stuff happens after the page has loaded - if this behaviour applies also to Ajax, long-polling, or socket-based apps then your users have the potential either to crash the database, cause the server to 'block" or send your bandwidth usage into a part of the stratosphere where it would pose a danger to low-orbiting satellites...therefore not using the session support for the time being (and letting your own route handlers manage it) would seem to be a good idea until this is patched.
Many thanks for the feedback. I've actually implemented a local object which caches the profile for a user as a temp solution. This will not work once in production and there are more than one users on the site. I'll keep an eye out for the patch.
this should work for you:
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) { return res.redirect('/login') }
req.session.user = user;
return res.redirect('/' );
})(req, res, next);
});
just stick the authentication response in the session :-) in the route handler for e.g. '/' route you can pull the user out of the session and do whatever you need. in my app, i'm using the express session and have disabled the passport session, keeping just the authentication part, and it works a treat. for bonus points, write a tiny module that will pull that user out of the session and do specific things with it depending on which route you're working with. also NB...replace the standard logout handling with this:
app.get('/logout', function(req, res){
//req.logout();//commented out the logout() call as passport is no longer handling the session
req.session.user = null;
res.redirect('/');
});
cheers!
How about something like this. Working for me.
exports.serializeUser = function(user, done) {
return done(null, user);
};
exports.deserializeUser = function(user, done) {
return done(false, user);
};
@minimok Is correct in his analysis. This is most likely happening because requests for your assets (images, CSS, JavaScript, etc.) are passing through the middleware stack and triggering passport.session()
app.configure(function() {
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
// passport session is triggered, causing deserializeUser to be invoked
app.use(passport.session());
// but request was for a static asset, for which authentication is not
// necessary
app.use(express.static(__dirname + '/../../public'));
});
The solution for this is to use express.static above passport.session (and express.session for maximum benefit)
app.configure(function() {
app.use(express.logger())
// requests for static assets will be handled immediately and will not continue
// down the middleware stack
app.use(express.static(__dirname + '/../../public'));
// any request that gets here is a dynamic page, and benefits from session
// support
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
});
Both Connect and Express used to provide examples with static middleware at the bottom, and Passport followed that practice. However, with Connect 2.0, the examples are now reflecting the latest thinking which is to use static middleware early in the chain. This addresses issues such as this one, and I'll be updating Passport's own docs soon.
I've toyed with the idea of adding an exclude paths option to passport.session() (see #4 for further discussion), but I can't really find a compelling reason to do so. If anyone can suggest a use case that would benefit from an exclude option, I'd be happy to implement it. Until then, the fix for this is using static middleware before session middleware.
express.static might not be a solution in cases where it is not used.
The most reason for double trigger, as middleware will process every request to API. And browsers usually do extra requests, for example /favicon.ico. So in order to prevent that, you can add middleware early in express.configure:
app.use(function(req, res, next) {
if (req.url != '/favicon.ico') {
return next();
} else {
res.status(200);
res.header('Content-Type', 'image/x-icon');
res.header('Cache-Control', 'max-age=4294880896');
res.end();
}
});
For projects relying on the flexibility of asset directories such as Sails, moving asset routing (express.static) to the top slows document responses.
Using Nginx to serve assets is a great alternative.
@Boycce can you provide some more insight into how to handle this for sails?
I just keep the flow of the http config normal, as is.
_sails.config.http_
middleware: {
order: [
'cookieParser',
'session',
'passport',
'passportSession',
'bodyParser',
'handleBodyParserError',
'methodOverride',
'poweredBy',
'$custom',
'router',
'www',
'favicon',
'404',
'500'
]
}
Then when requests are sent to my sever, i route them first through Nginx to sort assets from views/pages via location directives. From this setup, asset requests never hit node, which are the source of the _x10 deserializeUser_ issue.
FYI, requests failed to find assets would also pass to passport middleware even if using static middleware above.
Thanks for the fix @jaredhanson, this is really useful as it prevents the calls to mongoose for finding the user - this is ugly in the logs and a pointless overhead 馃檲
Mongoose: users.findOne({ _id: ObjectId("5904b44a615a277b67c14168") }, { fields: {} })
Mongoose: users.findOne({ _id: ObjectId("5904b44a615a277b67c14168") }, { fields: {} })
Mongoose: users.findOne({ _id: ObjectId("5904b44a615a277b67c14168") }, { fields: {} })
Most helpful comment
@minimok Is correct in his analysis. This is most likely happening because requests for your assets (images, CSS, JavaScript, etc.) are passing through the middleware stack and triggering
passport.session()The solution for this is to use
express.staticabovepassport.session(andexpress.sessionfor maximum benefit)Both Connect and Express used to provide examples with static middleware at the bottom, and Passport followed that practice. However, with Connect 2.0, the examples are now reflecting the latest thinking which is to use static middleware early in the chain. This addresses issues such as this one, and I'll be updating Passport's own docs soon.
I've toyed with the idea of adding an
excludepaths option topassport.session()(see #4 for further discussion), but I can't really find a compelling reason to do so. If anyone can suggest a use case that would benefit from anexcludeoption, I'd be happy to implement it. Until then, the fix for this is using static middleware before session middleware.