Using HTTP basic auth for certain URLs only with E

2020-08-18 05:19发布

问题:

I have a node.js application designed using the Express framework and the http-auth module, as follows:

var auth = require('http-auth');
var express = require('express');
// ...
var mywebapp = express();
// ...
if (usebasicauth) {
  var basic = auth.basic({realm:"MyRealm", file:"/srv/config/passwd"});
  mywebapp.use(auth.connect(basic));
}

mywebapp.use('/js', express.static(__dirname + '/files/js'));
mywebapp.use('/css', express.static(__dirname + '/files/css'));
// ...

However, I don't want to protect assets available under the /js and /css directories. This is what I tried doing:

if (usebasicauth) {
  var basic = auth.basic({realm:"MyRealm", file:"/srv/config/passwd"});
  mywebapp.use(function(req, res, next) {
    if (/^\/(css|js)/.test(req.url)) {
      next();
    }
    else {
      auth.connect(basic);
    }
  });
}

Trying to access URLs under /css and /js work as expected; however, other URLs never load.

How can I make other URLs work as expected?

回答1:

The order of mywebapp.use is important. If you have first mywebapp.use(auth.connect(basic)); then it will be used for every request but if you change the order it will pass statics and be only used for whatever is after it.

The middleware functions are processed in order they are added.

So following should do what you want.

// no auth for statics
mywebapp.use('/js', express.static(__dirname + '/files/js'));
mywebapp.use('/css', express.static(__dirname + '/files/css'));
// auth reguired from here 
mywebapp.use(auth.connect(basic));

If you place mywebapp.use(auth.connect(basic)); above express.static it will reguire auth for it as well.

// auth reguired from here 
mywebapp.use(auth.connect(basic));
// auth required for statics as well
mywebapp.use('/js', express.static(__dirname + '/files/js'));
mywebapp.use('/css', express.static(__dirname + '/files/css'));


回答2:

You can do something like this as well https://gist.github.com/gevorg/7168d5f02c1ca5362b2a#file-specific-path-js

// Express module.
var express = require('express');

// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
    realm: "Simon Area.",
    file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});

// Application setup.
var app = express();
app.use(function(req, res, next) {
    if ('/specific/path' === req.path) {
        next();
    } else {
        (auth.connect(basic))(req, res, next);
    }
});

// Setup route.
app.get('/', function(req, res){
  res.send("Hello from express - " + req.user + "!");
});

// Setup guest route.
app.get('/specific/path', function(req, res){
  res.send("Hello from express - guest!");
});

// Start server.
app.listen(1337);


回答3:

The accepted answer to this question is not desirable, as the route order can be important!

A better way to do it would be to pass basic-auth as second argument for your route definition:

app.get('/admin', auth.connect(basic), (req, res) => {
    res.send(`Hello from admin area - ${req.user}!`);
});

Or

app.use('/admin', auth.connect(basic), myCustomRoute);