如何访问basicAuth中的快速路由

时间:2014-06-01 05:13:38

标签: node.js express

我的NodeJS服务器,使用express,有一堆条目来指定各种路由:

app.post('list_streams.json',    auth, stream_handler.list_streams);
app.post('add_stream.json',      auth, stream_handler.add_stream);
app.post('delete_stream.json',   auth, stream_handler.delete_stream);
etc...

auth中间件是这样编写的:

var auth = express.basicAuth(function(user, pass, callback) {     
    user_handler.authenticate_user(user, pass, callback);
});

在user_handler.authenticate_user()函数内,执行对数据库的访问以验证用户。我想添加一些统计信息并跟踪特定用户执行的每个访问。我想在authenticate_user()函数中执行此操作,因为这是访问用户记录的数据库,我可以使用相同的访问权限来更新用户记录中的统计信息,但我需要以某种方式传递authenticate_user()的额外参数,指定执行的访问类型;路由本身或一些标识正在访问的路由的令牌。我无法弄清楚如何做到这一点。 “req”在authenticate_user()函数中不可用。

谢谢你, 加里

1 个答案:

答案 0 :(得分:1)

我不确定您的身份可以通过authenticate_user函数轻松完成,因为在首次访问任何用户时,每个会话只调用一次。

记录每个用户的ALL访问权限的最佳方法是创建一个新的中间件函数,如本文末尾所述。

但假设您只希望记录用户身份验证,解决问题的一种方法是将express.basicAuth替换为您自己的版本,该版本将回调函数绑定到快速req对象,如下所示:

var util=require('util'),
    express=require('express'),
    app=express(),
    auth=basicAuth(function(username,password,next){
        console.log('auth has access to req as "this": %s',util.inspect(this));
    });

app.get('/',auth,function(req,res){
    console.log('in request for "/", req is: %s',util.inspect(req));
    res.send('SUCCESS');
});

app.listen(4000,function(){
    console.log('running');
});

// Replacement for connect.basicAuth (as used by express)
// lifted from https://github.com/expressjs/basic-auth-connect

function unauthorized(res, realm) { // required by basicAuth
  res.statusCode = 401;
  res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
  res.end('Unauthorized');
}

function error(code, msg){ // required by basicAuth
  var err = new Error(msg || http.STATUS_CODES[code]);
  err.status = code;
  return err;
}

// replacement basic auth which binds the callback to the "req" object
function basicAuth(callback, realm) {
  var username, password;

  // user / pass strings
  if ('string' == typeof callback) {
    username = callback;
    password = realm;
    if ('string' != typeof password) throw new Error('password argument required');
    realm = arguments[2];
    callback = function(user, pass){
      return user == username && pass == password;
    }
  }

  realm = realm || 'Authorization Required';

  return function(req, res, next) {
    var authorization = req.headers.authorization;

    // 20140601 RR - !!NOTE!! bind callback to req
    callback=callback.bind(req);

    if (req.user) return next();
    if (!authorization) return unauthorized(res, realm);

    var parts = authorization.split(' ');

    if (parts.length !== 2) return next(error(400));

    var scheme = parts[0]
      , credentials = new Buffer(parts[1], 'base64').toString()
      , index = credentials.indexOf(':');

    if ('Basic' != scheme || index < 0) return next(error(400));

    var user = credentials.slice(0, index)
      , pass = credentials.slice(index + 1);

    // async
    if (callback.length >= 3) {
      callback(user, pass, function(err, user){
        if (err || !user)  return unauthorized(res, realm);
        req.user = req.remoteUser = user;
        next();
      });
    // sync
    } else {
      if (callback(user, pass)) {
        req.user = req.remoteUser = user;
        next();
      } else {
        unauthorized(res, realm);
      }
    }
  }
}

如果你看一下标有&#34; !!注意!!&#34;在上面,您将看到传递给新basicAuth函数的回调已被绑定表达&#39; req请求对象,它使this的想法成为对请求的引用。

现在您需要做的就是引用this.url以获取原始请求网址并进行记录。

如上所述,需要注意的一点是,auth的回调仅被调用以对用户进行一次身份验证。

后续请求已经设置了req.user HTTP头变量,因此允许请求通过而不调用身份验证回调。

这就是为什么记录特定用户的所有交互的最佳方法是在调用auth之后添加您自己的中间件,例如:

function logUser(req,res,next){

   // since this middleware is called AFTER auth, the user is already authorized.
   log.info('user "'+req.user+'" called url:'+req.url);

   next(); // pass control to the next stage in fulfilling the request
}

app.get('/',auth,logUser,function(req,res){
    ...
});