我的 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()函数中不可用。
谢谢你, 加里
最佳答案
我不确定您需要什么可以通过您的authenticate_user函数轻松完成,因为它在任何用户第一次访问时每个 session 仅调用一次。
记录每个用户的所有访问的最佳方法是创建一个新的中间件函数,如本文末尾所述。
但是假设您只想记录用户身份验证,解决问题的一种方法是将express.basicAuth 替换为您自己的版本,该版本将回调函数绑定(bind)到express 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);
}
}
}
}
如果您查看标有“!!NOTE!!”的行在上面,您将看到传递给新 basicAuth 函数的回调已绑定(bind)到 express 的 req
请求对象,这使得其 this
的概念成为对请求的引用。
现在您需要做的就是引用 this.url
来获取原始请求 URL 并记录它。
如上所述,需要注意的一件事是对 auth
的回调仅被调用以对用户进行一次身份验证。
后续请求已经设置了 req.user HTTP header 变量,因此允许请求通过,而无需调用身份验证回调。
这就是为什么记录特定用户的所有交互的最佳方法是在调用 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){
...
});
关于node.js - 如何访问 basicAuth 内的快速路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23976965/