我在 StackOverflow 上发现了一个类似的问题,但在获得提供的答案时遇到了一些麻烦。我将其转换为中间件以使其更适合:
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
从未设置。我被难住了,直到我遇到了这个 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 一个正确的答案,因为他的解决方案不仅可以完美运行,而且使用更少(更简单)的代码来实现,并且如果他们偶然发现了这个问题,它将更适合其他人的项目.