【问题标题】:HTTP Auth with dynamic URLs in Express.JSExpress.JS 中带有动态 URL 的 HTTP Auth
【发布时间】:2013-05-14 04:53:39
【问题描述】:

我在我的 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');
});

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

【问题讨论】:

    标签: node.js express http-authentication


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我在 StackOverflow 上找到了 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});
          });
      });
      

      但是,我将给 Robert 一个正确的答案,因为他的解决方案不仅完美运行,而且使用更少(更简单)的代码来实现目标,并且如果其他人的项目出现问题,它会更好地适应他们的项目这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-13
        • 1970-01-01
        相关资源
        最近更新 更多