问题
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 for the username and password (as expected), but after I correctly enter them, I'm given a 404. If I remove the authentication check and serve up the same directory, I actually get the pages contained within it.
Here's a quick server I whipped up as a proof-of-concept:
var express = require('express');
var app = express();
var auth = express.basicAuth(function(user,pass) {
return 'user' === user && 'pass' === pass;
});
app.use('/admin', auth, express.static(__dirname + '/admin'));
app.use('/adminNoAuth', express.static(__dirname + '/admin'));
app.listen(8082);
When I hit localhost:8082/admin
I get the username/password, then a 404. When I hit localhost:8082/adminNoAuth
it serves up the page.
I'm using Express 3.4.7 and node.js 0.10.22.
回答1:
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.
回答2:
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
回答3:
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.
来源:https://stackoverflow.com/questions/21170253/cannot-use-basic-authentication-while-serving-static-files-using-express