我的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()函数中不可用。
谢谢你, 加里
答案 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){
...
});