2

我的 Express 3.0 应用程序中有一条路线,定义如下:

app.post('/:app/find', auth, function(req, res){

我希望它限制使用 HTTP 授权。我的auth功能看起来像这样:

var auth = express.basicAuth(function(user, pass, callback){
    callback(null, user === 'user' && pass === 'pass');
});

我希望该函数根据URLauth进行数据库查找,并相应地对用户进行身份验证。req.params.app问题是我不确定如何访问它,因为在运行app.post时尚未调用定义的函数auth。我在哪里可以得到它?我应该使用不同的 HTTP 身份验证实现吗?

4

2 回答 2

4

没有正确的方法来做到这一点express.basicAuth(我还查看了一些其他提供类似功能的模块,但它们似乎也从未传递req给身份验证功能),但是您可以创建一个中间件,为每个请求实例化它您要进行身份验证:

var express = require('express');
var app     = express();

var basicAuth = express.basicAuth;
var auth      = function(req, res, next) {
  ...here you can access 'req'...
  basicAuth(function(user, pass, callback) {
    ...here you can use variables set in the block above...
    callback(null, user === 'user' && pass === 'pass');
  })(req, res, next);
};

app.get('/', auth, function(req, res) {
  res.send('authenticated!');
});

app.listen(3012);
于 2013-05-14T06:49:40.093 回答
0

我在 StackOverflow 上发现了一个类似的问题,但在获得提供的答案时遇到了一些麻烦。我将其转换为中间件以使其更适合:

var includeAuth = function(req, res, next){
    var header = req.header('authorization', false);
    if(header){
        var token = header.split(/\s+/).pop() || '';
        if(token.length > 0){
            var auth = new Buffer(token, 'base64').toString(),
                parts = auth.split(/:/);
            req.auth = {user: parts[0], pass: parts[1]};
        }else
            req.auth = false;
    }else
        req.auth = false;
    next();
}

app.configure(function(){
    app.use(includeAuth);
});

...但req.header.authorization从未设置。我被难住了,直到我遇到了这个 gist,这暗示了即使客户端正在发送授权标头,我仍然必须请求它们。所以我添加了这个:

if(req.auth){
        // Do things
}else{
    res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
    res.statusCode = 401;
    res.end("NO_CREDENTIALS");
}

然后我开始在 中查看数据req.auth,但该对象具有属性“用户名”和“密码”,而不是我指定的“用户”和“密码”。再四处寻找之后,我发现……那些是 Express 自动放在那里的!反正看起来是这样。我创建了一个没有任何中间件或其他装饰的新应用程序,并且得到了相同的结果,只要我发送了 WWW-Authenticate 标头。这使我的includeAuth中间件功能无用。有了我新发现的知识,我现在可以在客户端尝试进行身份验证时使用以下内容向客户端提供特定的错误消息:

function verifyAuth(req, res, appName, callback){
    if(req.auth){
        db.apps.findOne({id: appName}, function(err, app){ // Call to MongoDB
            if(!err && app){
                if(app.user === req.auth.username && app.pass === req.auth.password)
                    callback(null, true);
                else
                    callback("INVALID_CREDENTIALS", false);
            }else
                callback("NO_SUCH_APP", false);
        });
    }else{
        res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
        res.statusCode = 401;
        res.end(JSON.stringify({success: false, error: "NO_CREDENTIALS"}));
        callback(null, false);
    }
}

app.post('/:app/find', function(req, res){
    verifyAuth(req, res, req.params.app, function(err, allowed){
        if(!err && allowed){
            // Do some things
        }else if(err)
            res.send({success: false, error: err});
    });
});

但是,我将给 Robert 一个正确的答案,因为他的解决方案不仅可以完美运行,而且使用更少(更简单)的代码来实现,并且如果他们偶然发现了这个问题,它将更适合其他人的项目.

于 2013-05-19T01:19:49.503 回答