使用Express.JS中的dynamicURL进行HTTP身份validation
我的Express 3.0应用程序中有一条路线,如下所示:
app.post('/:app/find', auth, function(req, res){
我希望使用HTTP授权进行限制。 我的auth
function看起来像这样:
var auth = express.basicAuth(function(user, pass, callback){ callback(null, user === 'user' && pass === 'pass'); });
我希望auth
函数根据URL中的req.params.app
进行数据库查找,并相应地对用户进行身份validation。 问题是,我不确定如何访问它,因为app.post
中定义的函数在auth
运行app.post
没有被调用。 我在哪里可以得到它? 是否有一个不同的HTTP身份validation我应该使用的实现?
用express.basicAuth
(我也看了一些提供类似function的其他模块,但是他们似乎也不会传递req
到authentication函数),但是你可以创build一个中间件来实例化它对于您要validation的每个请求:
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);
我在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
从未设置。 我被困住了,直到我遇到了这个要点 ,这暗示了即使客户正在发送授权标题,我仍然不得不要求他们。 所以我补充说:
if(req.auth){ // Do things }else{ res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"'); res.statusCode = 401; res.end("NO_CREDENTIALS"); }
然后,我开始在req.auth
看到数据,但是对象具有“username”和“password”属性,而不是我指定的“user”和“pass”属性。 多了一点点后,我发现…那些是由快递自动! 无论如何,似乎是这样。 我做了一个没有任何中间件或其他装饰的新应用程序,并得到了相同的结果,只要我发送了WWW-Authenticate标头。 这使得我的includeAuth
中间件function无用。 有了我的新知识,我现在可以使用以下方法在客户端尝试进行身份validation时向客户端提供特定的错误消息:
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}); }); });
然而,我要给罗伯特正确的答案,因为他的解决scheme不仅工作完美,而且使用更less(更简单)的代码到达那里,并且会更好地适应别人的项目,如果他们碰到这个问题。