Allow the creation of access token to be overriden

This commit is contained in:
Raymond Feng 2014-06-06 14:30:18 -07:00
parent d8c6f9d962
commit 6b4ebdf609
3 changed files with 60 additions and 11 deletions

View File

@ -2,14 +2,12 @@
* Module Dependencies. * Module Dependencies.
*/ */
var Model = require('../loopback').Model var loopback = require('../loopback')
, loopback = require('../loopback') , Model = loopback.Model
, path = require('path') , path = require('path')
, SALT_WORK_FACTOR = 10 , SALT_WORK_FACTOR = 10
, crypto = require('crypto') , crypto = require('crypto')
, bcrypt = require('bcryptjs') , bcrypt = require('bcryptjs')
, passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, BaseAccessToken = require('./access-token') , BaseAccessToken = require('./access-token')
, DEFAULT_TTL = 1209600 // 2 weeks in seconds , DEFAULT_TTL = 1209600 // 2 weeks in seconds
, DEFAULT_RESET_PW_TTL = 15 * 60 // 15 mins in seconds , DEFAULT_RESET_PW_TTL = 15 * 60 // 15 mins in seconds
@ -128,6 +126,22 @@ var options = {
var User = module.exports = Model.extend('User', properties, options); var User = module.exports = Model.extend('User', properties, options);
/**
* Create access token for the logged in user. This method can be overridden to
* customize how access tokens are generated
*
* @param [Number} ttl The requested ttl
* @callack {Function} cb The callback function
* @param {String|Error} err The error string or object
* @param {AccessToken} token The generated access token object
*/
User.prototype.createAccessToken = function(ttl, cb) {
ttl = Math.min(ttl || User.settings.ttl, User.settings.maxTTL);
this.accessTokens.create({
ttl: ttl
}, cb);
};
/** /**
* Login a user by with the given `credentials`. * Login a user by with the given `credentials`.
* *
@ -144,6 +158,7 @@ var User = module.exports = Model.extend('User', properties, options);
*/ */
User.login = function (credentials, include, fn) { User.login = function (credentials, include, fn) {
var self = this;
if (typeof include === 'function') { if (typeof include === 'function') {
fn = include; fn = include;
include = undefined; include = undefined;
@ -162,7 +177,7 @@ User.login = function (credentials, include, fn) {
return fn(err); return fn(err);
} }
this.findOne({where: query}, function(err, user) { self.findOne({where: query}, function(err, user) {
var defaultError = new Error('login failed'); var defaultError = new Error('login failed');
defaultError.statusCode = 401; defaultError.statusCode = 401;
@ -175,9 +190,7 @@ User.login = function (credentials, include, fn) {
debug('An error is reported from User.hasPassword: %j', err); debug('An error is reported from User.hasPassword: %j', err);
fn(defaultError); fn(defaultError);
} else if(isMatch) { } else if(isMatch) {
user.accessTokens.create({ user.createAccessToken(credentials.ttl, function(err, token) {
ttl: Math.min(credentials.ttl || User.settings.ttl, User.settings.maxTTL)
}, function(err, token) {
if (err) return fn(err); if (err) return fn(err);
if (include === 'user') { if (include === 'user') {
// NOTE(bajtos) We can't set token.user here: // NOTE(bajtos) We can't set token.user here:

View File

@ -35,8 +35,6 @@
"express": "~3.5.0", "express": "~3.5.0",
"strong-remoting": "~1.5.0", "strong-remoting": "~1.5.0",
"inflection": "~1.3.5", "inflection": "~1.3.5",
"passport": "~0.2.0",
"passport-local": "~1.0.0",
"nodemailer": "~0.6.5", "nodemailer": "~0.6.5",
"ejs": "~1.0.0", "ejs": "~1.0.0",
"bcryptjs": "~0.7.12", "bcryptjs": "~0.7.12",

View File

@ -1,6 +1,5 @@
var User; var User;
var AccessToken = loopback.AccessToken; var AccessToken = loopback.AccessToken;
var passport = require('passport');
var MailConnector = require('../lib/connectors/mail'); var MailConnector = require('../lib/connectors/mail');
var userMemory = loopback.createDataSource({ var userMemory = loopback.createDataSource({
@ -9,6 +8,7 @@ var userMemory = loopback.createDataSource({
describe('User', function(){ describe('User', function(){
var validCredentials = {email: 'foo@bar.com', password: 'bar'}; var validCredentials = {email: 'foo@bar.com', password: 'bar'};
var validCredentialsWithTTL = {email: 'foo@bar.com', password: 'bar', ttl: 3600};
var invalidCredentials = {email: 'foo1@bar.com', password: 'bar1'}; var invalidCredentials = {email: 'foo1@bar.com', password: 'bar1'};
var incompleteCredentials = {password: 'bar1'}; var incompleteCredentials = {password: 'bar1'};
@ -117,6 +117,44 @@ describe('User', function(){
done(); done();
}); });
}); });
it('Login a user by providing credentials with TTL', function(done) {
User.login(validCredentialsWithTTL, function (err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.ttl, validCredentialsWithTTL.ttl);
assert.equal(accessToken.id.length, 64);
done();
});
});
it('Login a user using a custom createAccessToken', function(done) {
var createToken = User.prototype.createAccessToken; // Save the original method
// Override createAccessToken
User.prototype.createAccessToken = function(ttl, cb) {
// Reduce the ttl by half for testing purpose
this.accessTokens.create({ttl: ttl /2 }, cb);
};
User.login(validCredentialsWithTTL, function (err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.ttl, 1800);
assert.equal(accessToken.id.length, 64);
User.findById(accessToken.userId, function(err, user) {
user.createAccessToken(120, function (err, accessToken) {
assert(accessToken.userId);
assert(accessToken.id);
assert.equal(accessToken.ttl, 60);
assert.equal(accessToken.id.length, 64);
// Restore create access token
User.prototype.createAccessToken = createToken;
done();
});
});
});
});
it('Login a user over REST by providing credentials', function(done) { it('Login a user over REST by providing credentials', function(done) {
request(app) request(app)