'Use specific middleware in Express for all paths except a specific one
I am using the Express framework in node.js with some middleware functions:
var app = express.createServer(options);
app.use(User.checkUser);
I can use the .use
function with an additional parameter to use this middleware only on specific paths:
app.use('/userdata', User.checkUser);
Is it possible to use the path variable so that the middleware is used for all paths except a specific one, i.e. the root path?
I am thinking about something like this:
app.use('!/', User.checkUser);
So User.checkUser
is always called except for the root path.
Solution 1:[1]
I would add checkUser middleware to all my paths, except homepage.
app.get('/', routes.index);
app.get('/account', checkUser, routes.account);
or
app.all('*', checkUser);
function checkUser(req, res, next) {
if ( req.path == '/') return next();
//authenticate user
next();
}
You could extend this to search for the req.path in an array of non-authenticated paths:
function checkUser(req, res, next) {
const nonSecurePaths = ['/', '/about', '/contact'];
if (nonSecurePaths.includes(req.path)) return next();
//authenticate user
next();
}
Solution 2:[2]
You can set the middleware on each route also.
// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })
// POST /login gets urlencoded bodies
app.post('/login', urlencodedParser, function (req, res) {
if (!req.body) return res.sendStatus(400)
res.send('welcome, ' + req.body.username)
})
Solution 3:[3]
Instead of directly registering User.checkUser
as middleware, register a new helper function, say checkUserFilter
, that gets called on every URL, but passed execution to userFiled` only on given URLs. Example:
var checkUserFilter = function(req, res, next) {
if(req._parsedUrl.pathname === '/') {
next();
} else {
User.checkUser(req, res, next);
}
}
app.use(checkUserFilter);
In theory, you could provide regexp paths to app.use
. For instance something like:
app.use(/^\/.+$/, checkUser);
Tried it on express 3.0.0rc5, but it doesn't work.
Maybe we could open a new ticket and suggest this as a feature?
Solution 4:[4]
Use
app.use(/^(\/.+|(?!\/).*)$/, function(req, resp, next){...
This pass any url apart from /. Unless, it works for me.
In general
/^(\/path.+|(?!\/path).*)$/
(see How to negate specific word in regex?)
Hope this helps
Solution 5:[5]
Use this library called express-unless
Require authentication for every request unless the path is index.html.
app.use(requiresAuth.unless({
path: [
'/index.html',
{ url: '/', methods: ['GET', 'PUT'] }
]
}))
Path it could be a string, a regexp or an array of any of those. It also could be an array of object which is URL and methods key-pairs. If the request path or path and method match, the middleware will not run.
This library will surely help you.
Solution 6:[6]
The solution is to use order of setting api and middleware. In your case it must be something like this.
var app = express.createServer(options);
// put every api that you want to not use checkUser here and before setting User.checkUser
app.use("/", (req, res) => res.send("checkUser middleware is not called"));
app.use(User.checkUser);
// put every api that you want use checkUser
app.use("/userdata", User.checkUser, (req, res) =>
res.send("checkUser called!")
);
This is a full example.
const express = require("express");
const app = express();
const port = 3002;
app.get("/", (req, res) => res.send("hi"));
app.use((req, res, next) => {
console.log("check user");
next();
});
app.get("/checkedAPI", (req, res) => res.send("checkUser called"));
app.listen(port, () => {
console.log(`Server started at port ${port}`);
});
Solution 7:[7]
The solution by @chovy is the best.
Another solution is:
I was facing a similar problem. So what I did was to split the functions in the "routes" file into different files and export them separately. Likewise I imported them in the "server" file separately and called the middlewares for the respective routes. But I wouldn't recommend this on a large scale, I had a small project of less than 10 routes so I didn't mind doing it. For scaling I would go for chovy's method.
Solution 8:[8]
Thing that worked for me is to init single route you want before initializing for-all check, for example:
var app = express.createServer(options);
app.get('/', routes.index);
app.use(User.checkUser);
My personal example is this and works:
const app = express();
...
app.use('/api/flow', flowLimiter, flowRouter);
app.use(csurf({
cookie: false,
}));
...
So csurf
is applied an all routes except api/flow
- where I use sendBeacon, so I couldn't apply headers with tokens to it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Mohammad Yaser Ahmadi |
Solution 2 | |
Solution 3 | |
Solution 4 | Community |
Solution 5 | Abhay Shiro |
Solution 6 | |
Solution 7 | theBird |
Solution 8 | RomanistHere |