2013-05-14 64 views
2

动态网址我有一个路线中这样定义我的快车3.0的应用程序:HTTP认证与Express.JS

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

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

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

我想要auth功能做基于req.params.app从URL数据库查询,并相应地验证用户身份。问题是我不确定如何访问它,因为在运行auth时,尚未调用app.post中定义的函数。我在哪里可以得到它?是否有我应该使用的HTTP验证的不同实现?

回答

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); 
0

我发现这里a similar question在计算器上,但有一些麻烦提供工作答案。我把它转换到中间件,使之适合于更漂亮:

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从未设置过。我被困住了,直到我遇到了this 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}); 
    }); 
}); 

不过,我想给罗伯特正确的答案,因为他的解决方案不仅可以完美运行,而且可以使用更少(更简单)的代码来实现,并且可以更好地适应别人的项目,如果他们遇到了这个问题。