Reputation: 5220
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 ?
Upvotes: 37
Views: 42558
Reputation: 31
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.
Upvotes: 3
Reputation: 86
You could also chain middlewares as an array to achieve this goal:
app.use('/admin', [ensureAuthenticated, express.static(path.join(__dirname, 'admin'))]);
Upvotes: 3
Reputation: 3063
Update for [email protected]+
, [email protected]
, and [email protected]
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
])
Upvotes: 4
Reputation: 2604
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
Upvotes: 40
Reputation: 6986
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);
Upvotes: 14
Reputation: 15797
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();
});
Upvotes: 27