Skip to content

Commit

Permalink
feat(auth): add support for passport and authentication process purposal
Browse files Browse the repository at this point in the history
This commit add the ability to have built-in authentication process in a
hand clap time.
It relies on passport, jsonwebtoken, and mongo-connect.

It implements several features, for example an Auth service on client
side with ready to use methods such `login` and `signup`.

On a purposed future, this authentication process could be enrich with
some Oauth methods (connect with google, github...) or maybe a simple
lognup? To be continued...
  • Loading branch information
meriadec committed Feb 7, 2015
1 parent 3cd7a4f commit ef0cc50
Show file tree
Hide file tree
Showing 26 changed files with 649 additions and 39 deletions.
13 changes: 11 additions & 2 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,22 @@ var BangularGenerator = yeoman.generators.Base.extend({
}

if (props.backend === 'mongo') {
self.prompt({
self.prompt([{
type: 'confirm',
name: 'sockets',
message: 'Do you want to add socket support?',
default: false
}, function (props) {
}, {
type: 'confirm',
name: 'auth',
message: 'Do you want to scaffold a passport authentication process?',
default: false
}], function (props) {
self.filters.sockets = props.sockets;
self.filters.auth = props.auth;
if (props.auth) {
self.filters['ngCookies'] = true;
}
done();
});
} else {
Expand Down
3 changes: 2 additions & 1 deletion app/templates/#.jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"undef": true,
"unused": true,
"strict": true,
"maxparams": 3,
"maxdepth": 3,
"maxlen": 80,

Expand All @@ -35,6 +34,8 @@
"describe": true,
"inject": true,
"expect": true,
"afterEach": true,
"alert": true,
"beforeEach": true
}
}
38 changes: 35 additions & 3 deletions app/templates/client/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,45 @@ angular.module('<%= appname %>', [
'ngAnimate'<% } %><% if (filters.sockets) { %>,
'btford.socket-io'<% } %>
])
.config(function ($routeProvider, $locationProvider) {
.config(function ($routeProvider, $locationProvider<% if (filters.auth) { %>, $httpProvider<% } %>) {

$routeProvider
.otherwise({
redirectTo: '/'
});

$locationProvider.html5Mode(true);
$locationProvider.html5Mode(true);<% if (filters.auth) { %>
$httpProvider.interceptors.push('authInterceptor');<% } %>

});
})<% if (filters.auth) { %>
.factory('authInterceptor',
function ($rootScope, $q, $cookieStore, $location) {
return {

request: function (config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
},

responseError: function (response) {
if (response.status === 401) {
$location.path('/login');
$cookieStore.remove('token');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}

};
})

.run(function ($rootScope, Auth) {

$rootScope.Auth = Auth;

})<% } %>;
21 changes: 20 additions & 1 deletion app/templates/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,26 @@
</head>
<body>

<strong><%= appname %></strong>
<strong><%= appname %></strong><% if (filters.auth) { %>

<nav>
<ul>
<li>
<a href="/">home</a>
</li>
<li ng-if="!Auth.isLogged()">
<a href="/signup">signup</a>
</li>
<li ng-if="!Auth.isLogged()">
<a href="/login">login</a>
</li>
<li ng-if="Auth.isLogged()">
<a href="" ng-click="Auth.logout()">logout</a>
</li>
</ul>
</nav>

<pre>logged in: {{ Auth.isLogged() }}</pre><% } %>

<div ng-view></div>

Expand Down
84 changes: 84 additions & 0 deletions app/templates/client/services/auth(auth)/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use strict';

angular.module('<%= appname %>')
.service('Auth', function ($rootScope, $cookieStore, $q, $http) {

var _user = {};

if($cookieStore.get('token')) {
$http.get('/api/users/me')
.then(function (res) {
_user = res.data;
})
.catch(function (err) {
console.log(err);
});
}

/**
* Signup
*
* @param user
* @returns {promise}
*/
this.signup = function (user) {
var deferred = $q.defer();
$http.post('/api/users', user)
.then(function (res) {
_user = res.data.user;
$cookieStore.put('token', res.data.token);
deferred.resolve();
})
.catch(function (err) {
deferred.reject(err.data);
});
return deferred.promise;
};

/**
* Login
*
* @param user
* @returns {promise}
*/
this.login = function (user) {
var deferred = $q.defer();
$http.post('/auth/local', user)
.then(function (res) {
_user = res.data.user;
$cookieStore.put('token', res.data.token);
deferred.resolve();
})
.catch(function (err) {
deferred.reject(err.data);
});
return deferred.promise;
};

/**
* Logout
*/
this.logout = function () {
$cookieStore.remove('token');
_user = {};
};

/**
* Check if user is logged
*
* @returns {boolean}
*/
this.isLogged = function () {
return _user.hasOwnProperty('email');
};

/**
* Returns the user
*
* @returns {object}
*/
this.getUser = function () {
return _user;
};

});
34 changes: 34 additions & 0 deletions app/templates/client/services/auth(auth)/auth.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

describe('Service: Auth', function () {

beforeEach(module('<%= appname %>'));

var Auth,
$httpBackend,
$cookieStore;

beforeEach(inject(function (_Auth_, _$httpBackend_, _$cookieStore_) {
Auth = _Auth_;
$httpBackend = _$httpBackend_;
$cookieStore = _$cookieStore_;
$cookieStore.remove('token');
}));

afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});

it('should log user', function () {
expect(Auth.isLogged()).toBe(false);
Auth.login({ email: 'test@test.com', password: 'test' });
$httpBackend.expectPOST('/auth/local')
.respond({ token: 'abcde', user: { email: 'test@test.com' } });
$httpBackend.flush();
expect($cookieStore.get('token')).toBe('abcde');
expect(Auth.getUser().email).toBe('test@test.com');
expect(Auth.isLogged()).toBe(true);
});

});
32 changes: 32 additions & 0 deletions app/templates/client/views/login(auth)/login.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

angular.module('<%= appname %>')
.controller('LoginCtrl', function (Auth, $location) {

var vm = this;

angular.extend(vm, {

name: 'LoginCtrl',

/**
* User credentials
*/
user: { email: 'test@test.com', password: 'test' },

/**
* Login method
*/
login: function () {
Auth.login(vm.user)
.then(function () {
$location.path('/');
})
.catch(function (err) {
vm.error = err;
});
}

});

});
17 changes: 17 additions & 0 deletions app/templates/client/views/login(auth)/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div>
{{ vm.name }}
</div>

<form ng-submit="vm.login()">
<input type="email"
ng-model="vm.user.email"
placeholder="email">
<input type="password"
ng-model="vm.user.password"
placeholder="password">
<button type="submit">
login
</button>
</form>

<pre ng-if="vm.error">{{ vm.error | json }}</pre>
11 changes: 11 additions & 0 deletions app/templates/client/views/login(auth)/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

angular.module('<%= appname %>')
.config(function ($routeProvider) {
$routeProvider
.when('/login', {
templateUrl: 'views/login/login.html',
controller: 'LoginCtrl',
controllerAs: 'vm'
});
});
30 changes: 30 additions & 0 deletions app/templates/client/views/login(auth)/login.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

describe('Controller: LoginCtrl', function () {

beforeEach(module('<%= appname %>'));

var LoginCtrl,
$httpBackend,
$location;

beforeEach(inject(function ($controller, _$httpBackend_, _$location_) {
LoginCtrl = $controller('LoginCtrl', {});
$httpBackend = _$httpBackend_;
$location = _$location_;
}));

afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});

it('should redirect to / after successful login', function () {
LoginCtrl.login({ email: 'test@test.com', password: 'test' });
$httpBackend.expectPOST('/auth/local')
.respond({ token: 'token' });
$httpBackend.flush();
expect($location.path()).toBe('/');
});

});
32 changes: 32 additions & 0 deletions app/templates/client/views/signup(auth)/signup.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

angular.module('<%= appname %>')
.controller('SignupCtrl', function (Auth, $location) {

var vm = this;

angular.extend(vm, {

name: 'SignupCtrl',

/**
* User credentials
*/
user: { email: 'test@test.com', password: 'test' },

/**
* Signup
*/
signup: function () {
Auth.signup(vm.user)
.then(function () {
$location.path('/');
})
.catch(function (err) {
vm.error = err;
});
}

});

});
17 changes: 17 additions & 0 deletions app/templates/client/views/signup(auth)/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div>
{{ vm.name }}
</div>

<form ng-submit="vm.signup()">
<input type="email"
ng-model="vm.user.email"
placeholder="email">
<input type="password"
ng-model="vm.user.password"
placeholder="password">
<button type="submit">
signup
</button>
</form>

<pre ng-if="vm.error">{{ vm.error | json }}</pre>
11 changes: 11 additions & 0 deletions app/templates/client/views/signup(auth)/signup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

angular.module('<%= appname %>')
.config(function ($routeProvider) {
$routeProvider
.when('/signup', {
templateUrl: 'views/signup/signup.html',
controller: 'SignupCtrl',
controllerAs: 'vm'
});
});
Loading

0 comments on commit ef0cc50

Please sign in to comment.