NodeJS + session object in ALL views without passing it on all controller actions - node.js

I want my session to be available in all views (*.ejs) without having to pass it on every single action. My code is shown below, but the req.session object is always null here, even though in my "controllers" I can access a session object after an user has authenticated, by specifying:
req.session.whatever
My initialization code (that is currently executed on every single request (I double checked with a debug breakpoint) is:
var appendLocalsToUseInViews = function(req, res, next)
{
//append request and session to use directly in views and avoid passing around needless stuff
res.locals.request = req;
if(req.session != null && req.session.user != null)
{
res.locals.user = req.session.user;
}
next(null, req, res);
};
I register this function in the app setup preamble:
app.use(appendLocalsToUseInViews);
I have seen people use app.use methods and dynamicHelpers. I am using express 3, and it seems they are gone, deprecated from Express 2... But that does not seem to be the point, as the function is being called correctly on every single request. How to I access the Express session in this sort of pre-controller code?
Thanks!
SOLUTION thanks Jani Hartikainen:
I moved the code to after the session middleware is loaded and its working!!! Here is the new code.
app.use(express.cookieParser(appSecret));
app.use(express.session({ secret: appSecret }));
---->>>app.use(appendLocalsToUseInViews);

This should work but make sure your app.use for this is only after you have initialized your session middleware. If you have this before the initialization for the session middleware, it will be ran before it in the chain, and thus the data will not be available.

Related

Node Express auth status

I have multiple routes, split into different files (my app consists of different "modules", which I maintain in separate folders. For each folder, there is an index.js file in which I manage the routes per module, and I require these in the app.js file).
For every route, I will require to check the auth, and pass the loggedIn status to the header of every page:
//Default variables for the ejs template
var options = {
loggedIn: true
};
res.render("home/home", options);
If the logged in status is true, then the user's name will be displayed. If not, the login / signup labels are displayed.
What is the best way to centralise this, so that I don't need to require the auth script in every of these index.js (route) files?
I need to be able to pass the auth status to the view via the options object (see example).
In your auth, module, use a middleware function. That function can check and store res.locals.loggedIn which will be available for any view that will eventually be rendered. Just make sure the app.use call executes prior to your other routes and it will work properly.
app.use(function auth(req, res, next) {
res.locals.loggedIn = true; // compute proper value here
next();
});
From what I understand you need to do this for every request.One common thing is adding this as middleware so that all the request gets this .
For Example :
var http = require('http');
var connect = require('connect');
var app = connect();
app.use(function(req, res) {
res.end('Hello!');
});
http.createServer(app).listen(3000)
Now for every request , Hello is printed . You could extract this as a module and reuse it across projects. Check here for more details

Unable to register Express middleware

I'm trying to write a very basic piece of middleware for Express that checks to see if a user has some specified role required to access a resource. I have another piece of middleware that comes before this, which adds a user object to the request req for every route requiring authentication (and subsequent authorization).
As such, I define the authorization middleware like this:
_ = require('lodash');
function authorize(req, res, next, roles){
// check to see if user has one of the allowed roles
if(_.contains(roles, req.user.role)){
req.authorized = true;
return next();
}
// otherwise, pass an error
return next(new Error("Unauthorized"));
}
Every user object has a property called role on it, so I use _.contains(roles, req.user.role) to figure out whether or not the allowed roles contain the user's assigned role.
However, when I do this, I get TypeError: Cannot read property 'role' of undefined as soon as I start my Express server. This seems very weird to me, because I have not even made a request, and so of course req.user will be undefined until then.
Is there a way around this?
Example of how I use this middleware:
var app = express();
var router = express.Router();
router.get('/protected/:id', authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']), controllers.protected.retrieve);
When you register the route with
router.get(
'/protected/:id',
authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']),
controllers.protected.retrieve
)
the authorize method gets executed straight away by authorize(...) with the ['ADMINISTRATOR', ...] array being passed as the req param. Hence it is called as soon as you run the code and dies on user object not being present. Even if it didn't die on that, it wouldn't work as intended. You are mixing a middleware and a factory function together.
Express middleware is a function with a (req, res, next) signature, that you don't execute yourself. You need to pass a reference to such a middleware function and Express itself executes it on the request when needed, i.e.:
function authorize(req, res, next) {
...
};
router.get('/protected/:id', authorize, ...);
A parametrized middleware function, as in your case, can be easily created by splitting up to a factory and a middleware function:
// a factory function to create authorization middleware functions for given roles
function authorize(roles) {
// create and return an actual authorization middleware function
// to handle requests using the roles given when created
return function(req, res, next) {
if(_.contains(roles, req.user.role)){
req.authorized = true;
return next();
}
return next(new Error("Unauthorized"));
}
}
router.get(
'/protected/:id',
authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']),
controllers.protected.retrieve
)

Why does this flash policy module (express middleware) use _.clone() in Sails.js?

From a tutorial on Sails, this is a Sails policy - essentially Express middleware:
module.exports = function(req, res, next) {
res.locals.flash = {};
if (!req.session.flash) return next();
res.locals.flash = _.clone(req.session.flash)
// clear flash
req.session.flash = {};
next();
};
I'm totally lost:
What's the difference between req.locals.flash and req.session.flash?
Why do the response locals.flash have to be cleared right off the bat?
Why are response locals filled with cloned request session flash?
What's the difference between req.locals.flash and req.session.flash?
req.locals.flash will available in its view, but the req,session
relates with the session of browser.
More info locals vs session
Why do the response locals.flash have to be cleared right off the bat?
Make sure that the error message just display one time only.
Why are response locals filled with cloned request session flash?
Cause if not the locals will keep the pointer of the session. So if
the "req.session.flash = {};", the locals will also be empty
This is a policy, it will be invoked each time you visit a url(depends on your config/policies.js), what it does is to consume the message.
Clearing req.session.flash is to make sure the message is only displayed once, clearly you don't want to be haunted by the message again and again. :D
Hope that helps.

Node.js variables for current request only?

I am very new to Node.js, and I was wondering if that, except for session(), I could use a "storage" to store variables for the current request?
I have an API which is based on an Authorization header, and a pool of valid tokens stored in Redis.
Therefore I don't have a session and don't want to.
But I would like to store variables for further use during this request. For example, I would like to store the user_id corresponding to the token found in Redis, so that I can use it wherever I want.
If I do something like:
app = express();
app.user_id = 1;
Is it ok, or will my user_id become global to all requests handled by the app? (in short: is the app instanciated for each request handled by the server, or is it persistent?)
If this is not ok, how could I achieve something like this without sessions?
Thank you for any help :)
The app handles all requests, and would only be created once on startup, but req lives for only the lifetime of the request. Keep in mind that the req in Express is just an object, and as such, can be assigned values. So if you wanted to allow the controller to have access to some value (similar to sessions), you could do something like this:
var express = require('express');
var app = express();
// middleware that assigns a value '123' to 'req.user_id'
app.use(function(req, res, next) {
req.user_id = 123;
next();
});
// controller which responds with the 'req.user_id'
app.get('/hello', function(req, res){
res.send('req.user_id: ' + req.user_id); // responds with req.user_id: 123
});
app.listen(3000, function() {
console.log('Listening on port 3000');
});
In the above example, the middleware that I created assigns a value to the request, called user_id. This value lives for the life of the request. You could do a similar thing to assign a dynamic value to the req so that you can access it via your controllers.

NodeJS + Express: How to secure a URL

I am using latest versions of NodeJS and ExpressJS (for MVC).
I usually configure my rest paths like this, for example:
app.get('/archive', routes.archive);
Now i want my /admin/* set of URLs to be secured, I mean I need just simple authentication, it's just a draft.
When a user tries to access, for example, /admin/posts, before sending him the corresponding view and data, I check for a req.session.authenticated. If it's not defined, I redirect to the login page.
Login page has a simple validation form, and a sign-in controller method: if user does send "right user" and "right password" I set the session variable and he's authenticated.
What I find difficult, or I don't understand, is how to actually make the "filter" code, I mean, the auth check, before every /admin/* path call.
Does this have something to do with "middleware" express functions?
Thank you
Yep, middleware is exactly what you want. A middleware function is just a function that works just like any other Express route handler, expept it gets run before your actual route handler. You could, for example, do something like this:
function requireLogin(req, res, next) {
if (req.session.loggedIn) {
next(); // allow the next route to run
} else {
// require the user to log in
res.redirect("/login"); // or render a form, etc.
}
}
// Automatically apply the `requireLogin` middleware to all
// routes starting with `/admin`
app.all("/admin/*", requireLogin, function(req, res, next) {
next(); // if the middleware allowed us to get here,
// just move on to the next route handler
});
app.get("/admin/posts", function(req, res) {
// if we got here, the `app.all` call above has already
// ensured that the user is logged in
});
You could specify requireLogin as a middleware to each of the routes you want to be protected, instead of using the app.all call with /admin/*, but doing it the way I show here ensures that you can't accidentally forget to add it to any page that starts with /admin.
A even simpler approach would be to add the following code in the App.js file.
var auth = function(req, res, next) {
if(isAdmin) {
return next();
} else {
return res.status(400)
}
};
app.use('/admin', auth, apiDecrement);
As you can see the middleware is being attached to the route. Before ExpressJS goes forward, it executes the function that you passed as the second parameter.
With this solution you can make different checks before displaying the site to the end user.
Best.
Like brandon, but you can also go the connect route
app.use('/admin', requireLogin)
app.use(app.router)
app.get('/admin/posts', /* middleware */)

Resources