Using the Express framework for node.js, I\'m trying to serve up static files contained in a directory while also putting basic authentication on it. When I do so, I am prompted
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', auth)
app.use('/admin', express.static(__dirname + '/admin'));
EDIT
As of express version 4.x
you can pass in multiple middlewares as an array, or arguments, or mixture of both into app.use
. Making static files authorization safe would now be:
app.use( "/admin", [ auth, express.static( __dirname + "/admin" ) ] );
But both ways are still perfectly valid.
I thought I'd post the express 4 answer here, since there's no other post title as fitting as this one for this specific use-case, and it may be relevant for more people.
If you're using express 4, chances are you're using serve-index, serve-static, and http-auth (unless there's an easier way that I'm missing out on):
serveIndex = require('serve-index'),
serveStatic = require('serve-static'),
auth = require('http-auth');
// Basic authentication
var basic = auth.basic({
realm: "My Secret Place.",
}, function (username, password, callback) { // Custom authentication method.
callback(username === "me" && password === "mepassword");
}
);
var authMiddleware = auth.connect(basic);
// Serve /secretplace as a directory listing
app.use('/secretplace', authMiddleware, serveIndex(__dirname + '/public/secretplace'));
// Serve content under /secretplace as files
app.use('/secretplace', serveStatic(__dirname + '/public/secretplace', { 'index': false }));
Note, as far as my testing, I didn't need to pass 'authMiddleware' when setting serveStatic.
Im sharing how it worked out for me.
app.use("/login", (req, res, next) => {
if (req.cookies.UUID) {
res.redirect("/app");
} else {
next();
}
});
app.use("/login", express.static("dist_auth_app"));
app.use("/app", (req, res, next) => {
if (!req.cookies.UUID) {
res.redirect("/login");
} else {
next();
}
});
app.use("/app", express.static("dist"));
The answer:
var express = require("express")
var ss = require("serve-static")
var ba = require("basic-auth")
var app = express()
app.use("/", ss(__dirname + "/public"))
app.use(entry)
app.use("/privatesite", ss(__dirname + "/private"))
app.listen(4000)
function entry(req, res, next) {
var objUser = ba(req)
if (objUser === undefined || objUser.name !== "john" || objUser.pass !== "1234") {
res.set("WWW-Authenticate", "Basic realm=Authorization Required")
res.status(401).end()
} else { next() }
}
The 1st app.use() line offers the content of "public" folder in x.x.x.x:4000 ("/" route) to all visitors. The 3rd app.use() line offers the content of "private" folder in x.x.x.x:4000/privatesite ("/privatesite" route) only to user "john" because this line is written after 2nd app.use() line, which loads the authentication middleware. This authentication middleware uses "basic-auth" component, which returns an object with the name and pass written by client. If it is not "john" and "1234", server returns a 401 page; if it is, continue (thanks to next()) to 3rd app.use() line