Add loopback.token() middleware

This commit is contained in:
Ritchie Martori 2013-11-14 13:01:47 -08:00
parent 77a137eca6
commit 64d8ff986b
5 changed files with 89 additions and 17 deletions

View File

@ -11,18 +11,22 @@ var RemoteObjects = require('strong-remoting');
module.exports = token;
/**
*
*/
function token(app, options) {
options = options || {};
var tokenModelName = options.tokenModelName || 'Token';
var TokenModel = app.getModel(tokenModelName);
var tokenHeaderName = options.tokenHeaderName || 'X-Access-Token';
var tokenModelName = options.tokenModelName || 'AccessToken';
var TokenModel = options.model;
assert(TokenModel, 'loopback.token() middleware requires a AccessToken model');
return function (req, res, next) {
next();
TokenModel.findForRequest(req, options, function(err, token) {
if(err) return next(err);
if(token) {
req.accessToken = token;
next();
} else {
return next();
}
});
}
}

View File

@ -4,7 +4,8 @@
var Model = require('../loopback').Model
, loopback = require('../loopback')
, crypto = require('crypto');
, crypto = require('crypto')
, uid = require('uid2');
/**
* Default AccessToken properties.
@ -20,7 +21,7 @@ var properties = {
* Extends from the built in `loopback.Model` type.
*/
var AccessToken = module.exports = Model.extend('access-token', properties);
var AccessToken = module.exports = Model.extend('AccessToken', properties);
/**
* Create a cryptographically random access token id.
@ -29,7 +30,7 @@ var AccessToken = module.exports = Model.extend('access-token', properties);
*/
AccessToken.createAccessTokenId = function (fn) {
crypto.randomBytes(this.settings.accessTokenIdLength || 64, function(err, buf) {
uid(this.settings.accessTokenIdLength || 64, function(err, buf) {
if(err) {
fn(err);
} else {
@ -54,3 +55,64 @@ AccessToken.beforeCreate = function (next, data) {
}
});
}
/**
* Find a token for the given `ServerRequest`.
*
* @param {ServerRequest} req
* @param {Object} [options] Options for finding the token
* @param {Function} callback Calls back with a token if one exists otherwise null or an error.
*/
AccessToken.findForRequest = function(req, options, cb) {
var id = tokenIdForRequest(req, options);
if(id) {
this.findById(id, cb);
} else {
process.nextTick(function() {
cb();
});
}
}
function tokenIdForRequest(req, options) {
var params = options.params || [];
var headers = options.headers || [];
var cookies = options.cookies || [];
var i = 0;
var length;
var id;
params.push('access_token');
headers.push('X-Access-Token');
headers.push('authorization');
cookies.push('access_token');
cookies.push('authorization');
for(length = params.length; i < length; i++) {
id = req.param(params[i]);
if(typeof id === 'string') {
return id;
}
}
for(length = headers.length; i < length; i++) {
id = req.header(params[i]);
if(typeof id === 'string') {
return id;
}
}
for(length = headers.length; i < length; i++) {
id = req.signedCookies(cookies[i]);
if(typeof id === 'string') {
return id;
}
}
return null;
}

View File

@ -29,7 +29,8 @@
"ejs": "~0.8.4",
"bcryptjs": "~0.7.10",
"underscore.string": "~2.3.3",
"underscore": "~1.5.2"
"underscore": "~1.5.2",
"uid2": "0.0.3"
},
"devDependencies": {
"blanket": "~1.1.5",

View File

@ -10,12 +10,17 @@ describe('loopback.token(app, options)', function() {
it('should populate req.token from the query string', function (done) {
var app = loopback();
var options = {};
options.model = Token;
var testToken = this.token;
app.use(loopback.token(app, options));
app.get('/', function (req, res) {
assert(req.token === testToken);
try {
assert(req.accessToken, 'req should have accessToken');
assert(req.accessToken.id === testToken.id);
} catch(e) {
return done(e);
}
res.send('ok');
done();
});
request(app)
@ -32,4 +37,4 @@ function createTestingToken(done) {
test.token = token;
done();
});
}
}

View File

@ -103,7 +103,7 @@ describe('User', function(){
User.login({email: 'foo@bar.com', password: 'bar'}, function (err, accessToken) {
assert(accessToken.uid);
assert(accessToken.id);
assert.equal((new Buffer(accessToken.id, 'base64')).length, 64);
assert.equal(accessToken.id.length, 64);
done();
});
@ -121,7 +121,7 @@ describe('User', function(){
assert(accessToken.uid);
assert(accessToken.id);
assert.equal((new Buffer(accessToken.id, 'base64')).length, 64);
assert.equal(accessToken.id.length, 64);
done();
});