Regarding efficiency of passport.js module "deserializeUser" in node.js - javascript

So I was looking into the document regarding passport.js module serialize users to keep logged in users in session. (A little above the Username & Password parts). I'm using mongodb, with mongoose
passport.deserializeUser(function(id, done) {
console.log("this code is used again! ");
User.findById(id, function(err, user) {
done(err, user);
});
});
I test these code in example they gave. So it looks that this piece of code is executed every time when the logged-in user refresh a page.
Say there are 100,000 users and there are 10 pages in this entire application, it means there will be 1 million look-ups, just to maintain in session status for every one. Doesn't this sounds too inefficient? Does most application do this kind database search?
Or am I making mistaking understand it?

There's nothing stopping you from using a cache or similar approach. One of them could be https://www.npmjs.com/package/cache-manager but do shop for more!
Alternatively, if you don't really need to know all the user information all the time you can serialize/deserialize the user id only and load the user record on demand. In your instance just pass through function:
passport.deserializeUser(function(id, done) {
console.log("this code is used again! ");
done(null, id);
});
If that's not enough you could deserialize to an object like this:
passport.deserializeUser(function(id, done) {
console.log("this code is used again! ");
done(null, {id: id, user: function(done){
User.findById(id, function(err, user) {
done(err, user);
});
}});
});

Related

make session regeneration available to all login strategies method of passport

I am trying to implement session regeneration once the user logs-in to the application with the following code ,i am fairly able to implement.
passport.authenticate('local', function (err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else
{
req.login(user, function (err){
if (err) res.status(400).send(err);
else
{
req.session.regenerate(function(err)
{
if (err) console.log(err);
else{
//reset the cookie header with new session id
//return the user object
}
})
}
})
}
}
As Passport offers log-in through various strategies so i have to implement the same thing in all the other strategies ..I want to narrow it down with minimum code changes in the application ,I know i can place it in a method ..but is there some other solution which will affect all the login methods of all strategies which are implemented and which will be implemented in future.
Thanks in advance!

passport.js logs in one specific user, even though other user's username/password has been entered

I have the following code to authenticate users. When a username/password is not correct, passport.js doesn't allow to login which is as expected.
But when username/password is correct, passport.js always logs in one specific user regardless of the fact that another user's credentials have been entered. I wonder if anybody knows what might be the cause.
function authenticationMiddleware(){
return function(req,res,next){
console.log('req.isAuthenticated(): '+req.isAuthenticated())
if(req.isAuthenticated()){
return next()
}
res.redirect('/')
}
}
app.get('/profile', authenticationMiddleware(), (req, res) => {
res.render('profile.ejs',{
user: req.user
});
})
Console logs indicate that passport.js serializes the user whose credentials have been entered, however it always de-serializes one specific user regardless of entered credentials. I thought maybe my serializing and de-serializing methods are incorrect, but I couldn't find anything wrong with them:
passport.serializeUser(function(user, done) {
console.log('serializing user.username: '+user.username)
//return user by id (automatically generated id by CouchDB is _id)
done(null, user._id);
});
//
passport.deserializeUser(function(id, done) {
UserFindByID(id, function(err, user) {
console.log('deserializing user.username: '+user.username)
done(err, user);
});
});
UPDATE
There was a mistake in my UserFindByID function. I corrected the mistake and now the code works as expected.
Did you check that the id passed is correct? print it out before the UserFindByID. Maybe that function returns a wrong value

MongoDB update upon button click

Within my view, I am directing the user from '/dashboard' to '/upvote'
Within my routes, I have:
app.get('/upvote', function(req, res) {
user = req.user
user.score += 1;
user.save();
res.redirect('/dashboard');
});
This is just an example, trying to grasp how to use this for a different purpose at a later stage.
How do I correctly update my users 'score' attribute to increment every time there's a GET command for '/upvote/' ?
You need to find the given user in your request; req.user is just an object and not a mongoose model. If you have the ID of the document, you can use findById. If you don't you'll need to use a find query on another field.
// Users is the mongoose model
Users.findById(id, function (err, user) {
if (err) return handleError(err);
user.score += 1;
user.save(function(err) {
if (err) return handleError(err);
res.send(user); // Or redirect, basically finish request.
});
});
Second of all - I wouldn't necessarily do a redirect. You could stay on the same page and simply have the command refresh the user model.
If you separately modify and then save your user document, you can lose votes during concurrent requests.
Instead, use update with the $inc operator to make the upvote atomic:
app.get('/upvote', function(req, res) {
User.update({_id: req.user._id}, {$inc: {score: 1}}, function(err, count) {
res.redirect('/dashboard');
});
});
BTW, you should consider using a POST or PUT request instead of a GET as GET requests shouldn't change data.

Manage node-postgres query

I've read through node-postgresā€™s API documentation.
It recommended that we use the pg object to create pooled clients. And in pg.connect api documentation said:
The connect method retrieves a Client from the client pool, or if all
pooled clients are busy and the pool is not full, the connect method
will create a new client passing its first argument directly to the
Client constructor.
So according to the recommendation, does using pg.connect mean "using the pg object to create pooled clients"? If it's not, what does it actually mean?
And in my implementation example, I made several queries in my route:
app.get('/post', function(req, res) {
pg.connect(dbconfig, function(err, client, done) {
client.query('SELECT * FROM post', function(err, result) {
res.render('post/list', { posts: result.rows });
});
});
});
app.get('/post/new', function(req, res) {
res.render('post/new');
});
app.post('/api/v1/post', function(req, res) {
var b = req.body;
pg.connect(dbconfig, function(err, client, done) {
client.query('INSERT INTO post (title, content) VALUES ($1, $2)',
[b.title, b.content],
function(err, result) {
done();
res.redirect('/post');
});
});
});
Is it the right way to call pg.connect each time I want to make query? If not, what is the better idea?
It does look, according to the documentation that pg.connect() does handle pooled connections. I would suggest however one thing you could likely do better (assuming you only have one set of credentials your app is using).
If I were looking at doing this, I would work on saving duplication of effort/keystrokes/opportunities for error a bit and look at wrapping pg.connect() in some sort of function you could use that would return client. This would enable you to do something more like:
app.get('/post', function(req, res) {
db.run( function(client) {
client.query('SELECT * FROM post', function(err, result) {
res.render('post/list', { posts: result.rows });
});
});
});
However, given the way you have things done, I am not convinced you have a lot to gain by such an approach, so I don't see anything wrong with your approach.
This might be a little outdated now, but take a look at this:
https://github.com/aichholzer/Bodega
It will take care of any worries and make your coding experience a little more pleasant.
:)

Passport for authentication in Node JS

I am considering using the Passport Library (http://passportjs.org/) for authentication in a Node project.
I am confused by the following passport session functions:
passport.serializeUser(function( user, done ) {
done( null, user.id );
});
passport.deserializeUser(function( id, done ) {
user.get( id, function ( err, user ) {
done( err, user );
});
});
I am wondering:
1) Do these get called for every request that needs to be authenticated? Or are they just called once when the session is first created?
2) How do I access the information that is in "user" from other parts of my script?
3) For requests that need to be authenticated, where do I put any additional logic. eg To check if an allowable user idletime value has not been reached.
Thanks (in advance) for your help
1) serializeUser is called when creating a session for the user (when authentication was successful). This is used to store some sort of identifying information (like a unique user-id) about the user in an Express session.
deserializeUser is called for every request, and takes that piece of identifying information from the session to somehow convert it back to a full user record by means of a database query, perhaps, but that's really up to you: instead of just storing the user id you could also store the entire user record in the session, but it depends on the type of user record and the session storage you're using if that's possible (for example, using express.cookieSession would limit the amount of data you can store in a session).
This is what storing the entire user record could look like:
passport.serializeUser(function(user, done) {
// Here, 'user' is the result of the function called by 'new LocalStrategy()'; when
// you call done() below, that result will be stored in the session.
done(null, user);
});
passport.deserializeUser(function(user, done) {
// Here, 'user' is what's stored in the session by serializeUser()
done(null, user);
});
2) Passport populates req.user which you can use in routes or middleware.
3) You could make a middleware to implement such checks. This might be a good starting point.

Categories