views:

25

answers:

2

I have a node.js Express application with a basic user authentication system where the session is stored in redis. I'd like to write and re-use a current_user() function that populates a JSON representation of the logged in user (if there is one) in a current_user variable. Here is the code to retrieve the user:

if( req.cookie('fingerprint') ) {
  redis_client.get("users:fingerprint:"+req.cookie("fingerprint"), function(err,id) {
    redis_client.get("users:id:"+id, function(err,user) {
      current_user = JSON.parse(user);
    })
  })
}

if I only wanted to use this once, I could put a res.render call after that current_user line, but I'd like to populate the current_user variable for all controllers and actions.

I'm new to node, so there's probably a fundamental concept I'm missing here...but basically I need a way to return the current_user variable from above in a synchronous context or achieve the same effect asynchronously. For example,

app.get('/', function(req,res) {
  current_user = current_user();
  res.render('home', {layout: "layout.ejs", locals: {current_user: current_user}})
})

Thanks.

+2  A: 

Express routes accept a third argument: next, this allows you to pass control to the next matching route. You could use this to build up before filters based on routes, like:

app.get('/admin', function(req, res, next){
  if(authenticated_user()) {
    req.user = get_user();
    next(); 
  }
  else // prompt for login
});

app.get('/admin/:id', function(req, res){
  // foo
}

Hope this helps, for more information see Passing Route Control in the official Express guide

update

A DRYer way to achieve the same using the oh-so-cool Route Middleware

function checkAuthentication(req, res, next){
  if(authenticated_user()) {
    req.user = get_user();
    next(); 
  }
  else // prompt for login
}

app.get('/admin/:id', checkAuthentication, function(req, res){
  // foo
});
Daniel Mendel
yup Route Middleware is exactly what I was looking for! RTFM i guess :-/ Thanks Daniel
Neil Sarkar
+1  A: 

Why don't you just use dynamicHelpers?

firstly, store your current user in a session. Since you are using redis, check out something like the connect-redis for express. Then store it in session like so:

if( req.cookie('fingerprint') ) {
  redis_client.get("users:fingerprint:"+req.cookie("fingerprint"), function(err,id) {
    redis_client.get("users:id:"+id, function(err,user) {
      req.session.user = JSON.parse(user);
    })
  })
}

Make it available as a dynamicHelper:

app.dynamicHelpers({
   current_user: function(req) {
        return req.session.user;
   }
});

now current_user is available to all your route handlers as well as the views!

app.get('/admin/:id', function(req, res){
  if(current_user) {
     //do what you want here...
  }
});

on login, just regenerate the session like so:

req.session.regenerate(function() {
      // same as above!
  req.session.user = JSON.parse(user);
});

on logout, destroy the session:

req.session.destroy(function() {
  res.redirect('/');
});
Shripad K
also good to know, thanks Shripad! I marked Daniel's answer correct because it more directly answers the question of creating a before filter, but yours is more applicable to my use case and I'll be using this. thanks again.
Neil Sarkar
Sure! no problem :)
Shripad K