Disable session in Express app config - node.js

I am using Express with Passport for an Node.js API app, and I can disable sessions by passing {session:false} to passport.authenticate, but is there a way I can do this in one place so I don't repeat myself 600 times?
var app = express();
app.configure(function() {
app.use(express.bodyParser());
app.use(passport.initialize());
});
app.get('/users', passport.authenticate('hash', {session:false}), controllers.users.getAll);
app.get('/users/me', passport.authenticate('hash', {session:false}), controllers.users.getCurrentUser);
// and so on...
It would be great if I could just do:
app.donotuse(sessions).thanks();

Just save the result in a variable and re-use it:
var PassportAuthenticateMiddleware = passport.authenticate('hash', {session:false});
...
app.get('/users', PassportAuthenticateMiddleware, controllers.users.getAll);
app.get('/users/me', PassportAuthenticateMiddleware, controllers.users.getCurrentUser);
(or do as #hexacyanide suggests and use the middleware globally, if that's an option in your setup)
Alternatively, you can use something similar to this:
app.all('/users*', passport.authenticate('hash', {session:false}));
app.get('/users', controllers.users.getAll);
app.get('/users/me', controllers.users.getCurrentUser);
This will filter all requests (instead of .all you can use .get too) whose URL starts with /users to be run through the authentication middleware.

The authenticator itself is middleware. Therefore, you can assign it globally.
app.use(express.bodyParser());
app.use(passport.initialize());
app.use(passport.authenticate('hash', {session:false}));

I guess that you have some routes which need session. It is possible to set this globally, but this will not work in your case. What you can do is to improve the code a bit:
var controller = function(controller) {
return function(req, res, next) {
passport.authenticate('hash', {session:false})(req, res, next);
controller(req, res, next);
}
}
app.get('/users', controller(controllers.users.getAll));
app.get('/users/me', controller(controllers.users.getCurrentUser));

Related

Communication between middleware and route in keystonejs

I am using keystone and I have productDetail route in which I can add variables in res.locals to be used in templates. Is there a way I can use res.locals (of route file) in middleware.js file? As right now middleware is executing before route, I want route file to be executed first.
This is where middleware is executing in index.js file
keystone.pre('routes', middleware.initLocals);
And after that we have
exports = module.exports = function(app) {
// Views
app.get('/', routes.views.index);
app.get('/product-detail/:product', routes.views.productDetails);
}
I'm not sure if I got your question but this might help. You can run as many custom middleware you want after the middleware.initLocals (which apparently runs first). In your routes/middleware.js file, you can have, for example, two middleware:
exports.middleware0 = function (req, res, next) {
// Do some stuff
next();
};
exports.middleware1 = function (req, res, next) {
// Do some other stuff
next();
};
Then, inside your routes/index.js you can chain middleware together:
//...
var middleware = require('./middleware');
//...
exports = module.exports = function (app) {
// Use the middleware0 and middleware1:
app.get('/product-detail/:product', [middleware.middleware0, middleware.middleware1], routes.views.productDetails);
};

How to split a routes.js that grows too large to be easily maintained?

I'm using node and express to create a rest api. I followed a tutorial where all the routes and its logic are saved in a routes.js file like this:
SERVER JS:
var express = require('express');
var app = express();
(...)
require('./app/routes.js')(app, port, express);
ROUTES.JS
module.exports = function(app, port, express) {
var apiRoutes = express.Router();
(...)
//Sample route
apiRoutes.get('/userfiles', function(req, res) {
UserFile.find({ owner: req.decoded.user.email }, function(err, filesList) {
if (err)
return done(err);
res.json({ success: true, files: filesList });
});
});
My problem is twofold:
1 - Routes can easily contain code thats 150 lines long, some of them far longer. It doesn't feel clean to have route declarations and the logic grouped together. Is it a good practice to do something like this instead?
apiRoutes.post('/randomRoute', function(req, res) {
return res.json(functionThatContainsTheActualCode(req));
});
(and then have an functionThatContainsTheActualCode function with all the logic in a different file).
2 - I have middleware that applies to some functions (for example, some routes are only accessible for logged in users and those routes go through an authentication middleware). Currently way I do it is declaring public routes before the middleware declaration and private routes after, which feels incredibly hacky. How can I separate public and private routes (and the middleware itself) in different files?
Problem 1:
We need to go deeper.
Change the route file to just require the actual router logic.
routes.js
// where app = express();
module.exports = (app) => {
// index.js happens to be a file exporting the router.
app.use('/', require('./index'));
// this is basically the idea. Create a separate file for the actual logic.
app.use('/route', require('.path/to/file'));
};
and in file.js
const express = require('express'),
router = express.Router();
router.verb('/path/', (req, res, next) => {
// do whatever
});
// this is required
module.exports = router;
Problem 2:
Middleware is basically a function taking in request, response, next as 3 params, doing something with the request and either sending out a response or moving on to the next middleware. That's why you need to call next if you want to move to next middleware in the chain.
Now all you need is a file that exports a function which takes request, response, next as params.
// lets call this auth.js
module.exports = function(req, res, next) {
// do logic
if () {
return res.send(); // or res.somethingThatSendsOutAHttpResponse()
}
// next middelware
next();
};
Since express routes are also middlewares, (mind blown), you can mount them top down.
To authenticate a route, just put the auth.js middleware on top of that route.
router.get('/', require('./auth'));
router.get('/', require('./log'));
router.get('/', (req, res, next) => {
// yolo
});
Now since this is web dev, you still got problems.
Now all your boring database queries are scattered everywhere.
Fear not, you can solve it, by, guess, creating another file.
apiRoutes.get('/userfiles', function(req, res) {
const userFile = require('/path/to/model/with/userfile/methods/exported/out');
// do something with userFile's methods
});

Encapsulate Express Routers

Is it possible to create different routers using Express.Router that don't share middleware?
To me it seems that Express.Router uses a singleton, so no matter what I try, the middleware gets attached to all routers. So, without having to create multiple instances of the Express app, is there a way to achieve the following:
Create mutliple routers
var router_a = Express.Router();
var router_b = Express.Router();
Give each router unique routes and middleware
router_a.use(function(req, res, next){
console.log('Only works on router_a!');
});
router_a.get('/', function(req, res){
console.log('Only works on router_a!');
});
router_b.use(function(req, res, next){
console.log('Only works on router_b!');
});
router_b.get('/', function(req, res){
console.log('Only works on router_b!');
});
Attach each route to a custom url namespace
app.use('/a', router_a);
app.use('/b', router_b);
Is there a straight forward way to achieve this? After reading through the docs on the Router I don't see anything that suggests such is possible.
The one thing I see missing from your code is the call the next() in your middleware. If I add that to your code, it works perfectly fine for me.
The /b middleware is only called if the route starts with /b and same for the /a middleware with /a routes. And, to finish your code, you also have to send a response in your .get() handlers.
Here's the specific code I just tested:
var express = require('express');
var app = express();
var server = app.listen(80);
app.use(express.static('public'));
var router_a = express.Router();
var router_b = express.Router();
router_a.use(function(req, res, next){
console.log('.use() - Only works on router_a!');
next();
});
router_a.get('/', function(req, res){
console.log('.get() - Only works on router_a!');
res.send("router a, / route");
});
router_b.use(function(req, res, next){
console.log('.use() - Only works on router_b!');
next();
});
router_b.get('/', function(req, res){
console.log('.get() - Only works on router_b!');
res.send("router b, / route");
});
app.use('/a', router_a);
app.use('/b', router_b);

How to protect static folder in express with passport

I have a project based on express with a required authentication based on passport.
The backoffice is an angularjs app served as static files.
My authentication code is completly based on https://github.com/jaredhanson/passport-local/blob/master/examples/express3-no-connect-flash/app.js
To do not serve the angular app if you are not authenticated. I have try by adding ensureAuthenticated on the /admin route but it make the route not working (404). Once I remove ensureAuthenticated the /admin is served.
app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', ensureAuthenticated, express.static(path.join(__dirname, 'admin')));
//serve routes
app.use(app.router);
The public folder contains the login page.
How could I achieve this ?
Ran into same issue, this is what I ended up doing!
app.use doesn't let you chain middlewares in that way. The various
app.VERB functions do, but app.use doesn't. That's for one middleware
at a time.
If you split the 2 middlewares out into separate calls, you should get
the results you want:
app.use('/admin', ensureAuthenticated);
app.use('/admin', express.static(path.join(__dirname, 'admin')));
Cannot use basic authentication while serving static files using express
You can check the route using middleware and redirect them if they aren't logged in and are hitting admin pages, something like (untested):
app.use(function(req, res, next) {
if (req.user == null && req.path.indexOf('/admin') === 0)
{
res.redirect('/login');
}
next();
});
app.use('/admin', function(req,res,next){
if(req.user){
return express.static(path.join(__dirname, 'public'));
} else {
res.render(403, 'login', {message:'Please, login!'});
}
});
//serve routes
app.use(app.router);
Update for express#4.16.4+, passport-jtw#0.4.0, and passport-jwt#4.0.0
First setup a passport auth strategy. If you use a jwt, you can take a token from a query parameter, if not you can use another Extract function (or multiple using Jwt.ExtractJwt.fromExtractors())
passport.use('basic-user',
new Jwt.Strategy({
...jwtConfig.options,
jwtFromRequest: Jwt.ExtractJwt.fromUrlQueryParameter('token')
}, verifyUser)
);
Then you can use a passport authenticate function before serving static files
app.use('/files', [
passport.authenticate(['basic-user'], { session: false }),
express.static(path.join(__dirname, 'files')) //make sure you access proper directory
])
You could also chain middlewares as an array to achieve this goal:
app.use('/admin', [ensureAuthenticated, express.static(path.join(__dirname, 'admin'))]);
The accepted answer felt a bit partial (and may not work in some cases), so here's a bit more verbose and generalized answer:
// Here we'll attach the user object. The correct ordering
// of these middleware functions is important.
app.use(
'/some-restricted-static-path',
passport.authenticate("bearer", { session: false })
);
// As the user object should now be attached (if authorized), we can now
// verify it to be so.
app.use('/some-restricted-static-path', (req, res, next) => {
if (!!req.user) {
// The user exists, we can continue.
// Here you can also validate the role etc if necessary.
next();
} else {
// No user object found, terminate the pipeline with .end().
res.status(401).end();
}
});
// And finally, here's the actual handler that won't be accessed if
// something went wrong earlier.
app.use(
'/some-restricted-static-path',
express.static(
path.join(
__dirname,
"../dist/attachments"
)
)
);
Explanation: In Express, the middleware is processed one-by-one. If one of the middleware terminate the process, every middleware after it will be skipped. So, knowing this, we can first attach the user object, then validate it, and finally either grant or deny access.

Is it possible to set a base URL for NodeJS app?

I want to be able to host multiple NodeJS apps under the same domain, without using sub-domains (like google.com/reader instead of images.google.com). The problem is that I'm always typing the first part of the url e.g. "/reader" in Express/NodeJS.
How can I set up an Express app so that the base URL is something.com/myapp?
So instead of:
app.get("/myapp", function (req, res) {
// can be accessed from something.com/myapp
});
I can do:
// Some set-up
app.base = "/myapp"
app.get("/", function (req, res) {
// can still be accessed from something.com/myapp
});
I'd also like to configure Connect's staticProvider to behave the same way (right now it defaults to serving static files to something.com/js or something.com/css instead of something.com/myapp/js)
The express router can handle this since 4.0
http://expressjs.com/en/api.html#router
http://bulkan-evcimen.com/using_express_router_instead_of_express_namespace.html
var express = require('express');
var app = express();
var router = express.Router();
// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function(req, res, next) {
console.log('%s %s %s', req.method, req.url, req.path);
next();
});
// this will only be invoked if the path ends in /bar
router.use('/bar', function(req, res, next) {
// ... maybe some additional /bar logging ...
next();
});
// always invoked
router.use(function(req, res, next) {
res.send('Hello World');
});
app.use('/foo', router);
app.listen(3000);
Previous answer (before express 4.0) :
The express-namespace module (dead now) used to do the trick :
https://github.com/visionmedia/express-namespace
require('express-namespace');
app.namespace('/myapp', function() {
app.get('/', function (req, res) {
// can be accessed from something.com/myapp
});
});
At the moment this is not supported, and it's not easy to add it on your own.
The whole routing stuff is buried deep inside the server code, and as a bonus there's no exposure of the routes them selfs.
I dug through the source and also checked out the latest version of Express and the Connect middleware, but there's still no support for such functionality, you should open a issue either on Connect or Express itself.
Meanwhile...
Patch the thing yourself, here's a quick and easy way with only one line of code changed.
In ~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js, search for:
// Generate the route
this.routes[method](path, fn);
This should be around line 357, replace that with:
// Generate the route
this.routes[method](((self.settings.base || '') + path), fn);
Now just add the setting:
app.set('base', '/myapp');
This works fine with paths that are plain strings, for RegEx support you will have to hack around in the router middleware yourself, better file an issue in that case.
As far as the static provider goes, just add in /mypapp when setting it up.
Update
Made it work with RegExp too:
// replace
this.routes[method](baseRoute(self.settings.base || '', path), fn);
// helper
function baseRoute(base, path) {
if (path instanceof RegExp) {
var exp = RegExp(path).toString().slice(1, -1);
return new RegExp(exp[0] === '^' ? '^' + base + exp.substring(1) : base + exp);
} else {
return (base || '') + path;
}
}
I only tested this with a handful of expressions, so this isn't 100% tested but in theory it should work.
Update 2
Filed an issue with the patch:
https://github.com/visionmedia/express/issues/issue/478
Just to update the thread, now with Express.js v4 you can do it without using express-namespace:
var express = require('express'),
forumRouter = express.Router(),
threadRouter = express.Router(),
app = express();
forumRouter.get('/:id)', function(req, res){
res.send('GET forum ' + req.params.id);
});
forumRouter.get('/:id/edit', function(req, res){
res.send('GET forum ' + req.params.id + ' edit page');
});
forumRouter.delete('/:id', function(req, res){
res.send('DELETE forum ' + req.params.id);
});
app.use('/forum', forumRouter);
threadRouter.get('/:id/thread/:tid', function(req, res){
res.send('GET forum ' + req.params.id + ' thread ' + req.params.tid);
});
forumRouter.use('/', threadRouter);
app.listen(app.get("port") || 3000);
Cheers!
I was able to achieve this using a combination of express-namespace for the routes and a fix from the below google group discussion for the static assets. This snippet will treat a request to /foo/javascripts/jquery.js like a request to /javascripts/jquery.js:
app.use('/foo', express.static(__dirname + '/public'));
Source:
https://groups.google.com/forum/#!msg/express-js/xlP6_DX6he0/6OTY4hwfV-0J
I know this is a very old question but Express has changed a lot since most these answers were posted so I thought I'd share my approach.
You can, of course, use Routers with Express 4 to group together related functionality behind a particular path. This is well documented and has already been covered by other answers.
However, it is also possible to mount an entire application at a particular path. As an example, let's assume our application (the one we want to host at /myapp) looks like this, in a file called myapp.js:
var express = require('express'),
path = require('path'),
app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/hello', function(req, res) {
res.send('Hello');
});
// Lots of other stuff here
exports.app = app;
In our main js file we could then mount this whole application at the path /myapp:
var express = require('express'),
app = express(),
myApp = require('./myapp').app;
app.use('/myapp', myApp);
app.listen(3000);
Note that we've created two applications here, one mounted on the other. The main application could have further sub-apps mounted at different paths as required.
The code in myapp.js is completely independent of where it was mounted. It's similar to the structure used by the express-generator in that regard.
Some documentation about sub-apps can be found here:
https://expressjs.com/en/4x/api.html#app.mountpath
https://expressjs.com/en/4x/api.html#app.onmount
There are also reliability issues. If reliability is important, a common solution is to use a front-end reverse HTTP proxy such as nginx or HAProxy. They both use single-thread evented architecture and are thus very scalable.
Then you can have different node processes for different subsites, and if one site fails (uncaught exception, memory leak, programmer error, whatever) the rest of sub-sites continue to work.
I was looking for this feature but for API routes, not for static files. What I did was that when I initialized the router, I added the mount path. So my configuration looks like this
//Default configuration
app.configure(function(){
app.use(express.compress());
app.use(express.logger('dev'));
app.set('json spaces',0);
app.use(express.limit('2mb'));
app.use(express.bodyParser());
app.use('/api', app.router); // <---
app.use(function(err, req, res, callback){
res.json(err.code, {});
});
});
Notice the '/api' when calling the router

Resources