Add loopback.token() middleware
This commit is contained in:
parent
77a137eca6
commit
64d8ff986b
|
@ -11,18 +11,22 @@ var RemoteObjects = require('strong-remoting');
|
||||||
|
|
||||||
module.exports = token;
|
module.exports = token;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
function token(app, options) {
|
function token(app, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var tokenModelName = options.tokenModelName || 'Token';
|
var tokenModelName = options.tokenModelName || 'AccessToken';
|
||||||
var TokenModel = app.getModel(tokenModelName);
|
var TokenModel = options.model;
|
||||||
var tokenHeaderName = options.tokenHeaderName || 'X-Access-Token';
|
assert(TokenModel, 'loopback.token() middleware requires a AccessToken model');
|
||||||
|
|
||||||
return function (req, res, next) {
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
var Model = require('../loopback').Model
|
var Model = require('../loopback').Model
|
||||||
, loopback = require('../loopback')
|
, loopback = require('../loopback')
|
||||||
, crypto = require('crypto');
|
, crypto = require('crypto')
|
||||||
|
, uid = require('uid2');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default AccessToken properties.
|
* Default AccessToken properties.
|
||||||
|
@ -20,7 +21,7 @@ var properties = {
|
||||||
* Extends from the built in `loopback.Model` type.
|
* 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.
|
* Create a cryptographically random access token id.
|
||||||
|
@ -29,7 +30,7 @@ var AccessToken = module.exports = Model.extend('access-token', properties);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AccessToken.createAccessTokenId = function (fn) {
|
AccessToken.createAccessTokenId = function (fn) {
|
||||||
crypto.randomBytes(this.settings.accessTokenIdLength || 64, function(err, buf) {
|
uid(this.settings.accessTokenIdLength || 64, function(err, buf) {
|
||||||
if(err) {
|
if(err) {
|
||||||
fn(err);
|
fn(err);
|
||||||
} else {
|
} 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;
|
||||||
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
"ejs": "~0.8.4",
|
"ejs": "~0.8.4",
|
||||||
"bcryptjs": "~0.7.10",
|
"bcryptjs": "~0.7.10",
|
||||||
"underscore.string": "~2.3.3",
|
"underscore.string": "~2.3.3",
|
||||||
"underscore": "~1.5.2"
|
"underscore": "~1.5.2",
|
||||||
|
"uid2": "0.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"blanket": "~1.1.5",
|
"blanket": "~1.1.5",
|
||||||
|
|
|
@ -10,12 +10,17 @@ describe('loopback.token(app, options)', function() {
|
||||||
it('should populate req.token from the query string', function (done) {
|
it('should populate req.token from the query string', function (done) {
|
||||||
var app = loopback();
|
var app = loopback();
|
||||||
var options = {};
|
var options = {};
|
||||||
|
options.model = Token;
|
||||||
var testToken = this.token;
|
var testToken = this.token;
|
||||||
app.use(loopback.token(app, options));
|
app.use(loopback.token(app, options));
|
||||||
app.get('/', function (req, res) {
|
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');
|
res.send('ok');
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
request(app)
|
request(app)
|
||||||
|
@ -32,4 +37,4 @@ function createTestingToken(done) {
|
||||||
test.token = token;
|
test.token = token;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ describe('User', function(){
|
||||||
User.login({email: 'foo@bar.com', password: 'bar'}, function (err, accessToken) {
|
User.login({email: 'foo@bar.com', password: 'bar'}, function (err, accessToken) {
|
||||||
assert(accessToken.uid);
|
assert(accessToken.uid);
|
||||||
assert(accessToken.id);
|
assert(accessToken.id);
|
||||||
assert.equal((new Buffer(accessToken.id, 'base64')).length, 64);
|
assert.equal(accessToken.id.length, 64);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -121,7 +121,7 @@ describe('User', function(){
|
||||||
|
|
||||||
assert(accessToken.uid);
|
assert(accessToken.uid);
|
||||||
assert(accessToken.id);
|
assert(accessToken.id);
|
||||||
assert.equal((new Buffer(accessToken.id, 'base64')).length, 64);
|
assert.equal(accessToken.id.length, 64);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue