AngularJS User Registration and Login Example
Reference took from http://jasonwatmore.com/post/2015/03/10/AngularJS-User-Registration-and-Login-Example.aspx
Plunker link example : http://embed.plnkr.co/Mvrte4/preview
AngularJS User Registration and Login Example
Building on from a previous article I posted on how to implement Basic HTTP Authentication with AngularJS, in this post I've extended that example to include a simple user registration form.
The project is available on GitHub at https://github.com/cornflourblue/angular-registration-login-example
The example uses HTML5 local storage for storing the users so I could show it working without a back end, however the project also contains a user service built to interact with a RESTful web service. To switch from local storage to the web service implementation just update which script is embedded in the index.html file, note that for this to work you also need to create the RESTful web service for managing users :)
AngularJS Project Structure
I've based a lot of the project and code structure on recommendations from John Papa's style guide with my own tweaks here and there, for example I've placed application config and routes within the app.js file rather than separate files because there isn't much code in either section, these could be split out later if the sections grow.
I'm also trying out placing application services and content in folders prefixed with 'app-' to prevent having a name clash if I need to add a section to my app called 'services' or 'content', it also has the added benefit of grouping all the 'non-gui' code together at the top of the folders.
Here's what the project structure looks like:
app-content
app.css
app-services
authentication.service.js
flash.service.js
user.service.js
user.service.local-storage.js
home
home.controller.js
home.view.html
login
login.controller.js
login.view.html
register
register.controller.js
register.view.html
app.js
index.html
Below I've included brief descriptions of the main files that have to do with user registration and authentication, all the files are available at the github project linked at the top of the post.
AngularJS Authentication Service
Back to top
The authentication service contains methods for authenticating a user, setting credentials and clearing credentials from the HTTP "Authorization" headers used by the AngularJS $http service, so effectively logging in and out.
The example uses dummy authentication in order to show the example working on plunker without a back end, but real authentication can be setup by following the comments in the Login function.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
(function () {
'use strict';
angular
.module('app')
.factory('AuthenticationService', AuthenticationService);
AuthenticationService.$inject = ['$http', '$cookieStore', '$rootScope', '$timeout', 'UserService'];
function AuthenticationService($http, $cookieStore, $rootScope, $timeout, UserService) {
var service = {};
service.Login = Login;
service.SetCredentials = SetCredentials;
service.ClearCredentials = ClearCredentials;
return service;
function Login(username, password, callback) {
/* Dummy authentication for testing, uses $timeout to simulate api call
----------------------------------------------*/
$timeout(function () {
var response;
UserService.GetByUsername(username)
.then(function (user) {
if (user !== null && user.password === password) {
response = { success: true };
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
});
}, 1000);
/* Use this for real authentication
----------------------------------------------*/
//$http.post('/api/authenticate', { username: username, password: password })
// .success(function (response) {
// callback(response);
// });
}
function SetCredentials(username, password) {
var authdata = Base64.encode(username + ':' + password);
$rootScope.globals = {
currentUser: {
username: username,
authdata: authdata
}
};
$http.defaults.headers.common['Authorization'] = 'Basic ' + authdata; // jshint ignore:line
$cookieStore.put('globals', $rootScope.globals);
}
function ClearCredentials() {
$rootScope.globals = {};
$cookieStore.remove('globals');
$http.defaults.headers.common.Authorization = 'Basic ';
}
}
// Base64 encoding service used by AuthenticationService
var Base64 = {
keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this.keyStr.charAt(enc1) +
this.keyStr.charAt(enc2) +
this.keyStr.charAt(enc3) +
this.keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
},
decode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
if (base64test.exec(input)) {
window.alert("There were invalid base64 characters in the input text.\n" +
"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
"Expect errors in decoding.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = this.keyStr.indexOf(input.charAt(i++));
enc2 = this.keyStr.indexOf(input.charAt(i++));
enc3 = this.keyStr.indexOf(input.charAt(i++));
enc4 = this.keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
}
};
})();
AngularJS User Service
Back to top
A user service designed to interact with a RESTful web service to manage users within the system.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
(function () {
'use strict';
angular
.module('app')
.factory('UserService', UserService);
UserService.$inject = ['$http'];
function UserService($http) {
var service = {};
service.GetAll = GetAll;
service.GetById = GetById;
service.GetByUsername = GetByUsername;
service.Create = Create;
service.Update = Update;
service.Delete = Delete;
return service;
function GetAll() {
return $http.get('/api/users').then(handleSuccess, handleError('Error getting all users'));
}
function GetById(id) {
return $http.get('/api/users/' + id).then(handleSuccess, handleError('Error getting user by id'));
}
function GetByUsername(username) {
return $http.get('/api/users/' + username).then(handleSuccess, handleError('Error getting user by username'));
}
function Create(user) {
return $http.post('/api/users', user).then(handleSuccess, handleError('Error creating user'));
}
function Update(user) {
return $http.put('/api/users/' + user.id, user).then(handleSuccess, handleError('Error updating user'));
}
function Delete(id) {
return $http.delete('/api/users/' + id).then(handleSuccess, handleError('Error deleting user'));
}
// private functions
function handleSuccess(data) {
return data;
}
function handleError(error) {
return function () {
return { success: false, message: error };
};
}
}
})();
AngularJS Fake User Service (Local Storage)
Back to top
A fake user service that stores users in local storage in the browser, it mimics the behaviour of the real user service by returning promises and using $timeout.
When creating a user, the service checks if a username is already taken and returns an error message, in a real implementation using a web service this action would be performed on the server.
To switch between using this fake user service and the real one above update the scripts section at the bottom of the index.html file.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
(function () {
'use strict';
angular
.module('app')
.factory('UserService', UserService);
UserService.$inject = ['$timeout', '$filter', '$q'];
function UserService($timeout, $filter, $q) {
var service = {};
service.GetAll = GetAll;
service.GetById = GetById;
service.GetByUsername = GetByUsername;
service.Create = Create;
service.Update = Update;
service.Delete = Delete;
return service;
function GetAll() {
var deferred = $q.defer();
deferred.resolve(getUsers());
return deferred.promise;
}
function GetById(id) {
var deferred = $q.defer();
var filtered = $filter('filter')(getUsers(), { id: id });
var user = filtered.length ? filtered[0] : null;
deferred.resolve(user);
return deferred.promise;
}
function GetByUsername(username) {
var deferred = $q.defer();
var filtered = $filter('filter')(getUsers(), { username: username });
var user = filtered.length ? filtered[0] : null;
deferred.resolve(user);
return deferred.promise;
}
function Create(user) {
var deferred = $q.defer();
// simulate api call with $timeout
$timeout(function () {
GetByUsername(user.username)
.then(function (duplicateUser) {
if (duplicateUser !== null) {
deferred.resolve({ success: false, message: 'Username "' + user.username + '" is already taken' });
} else {
var users = getUsers();
// assign id
var lastUser = users[users.length - 1] || { id: 0 };
user.id = lastUser.id + 1;
// save to local storage
users.push(user);
setUsers(users);
deferred.resolve({ success: true });
}
});
}, 1000);
return deferred.promise;
}
function Update(user) {
var deferred = $q.defer();
var users = getUsers();
for (var i = 0; i < users.length; i++) {
if (users[i].id === user.id) {
users[i] = user;
break;
}
}
setUsers(users);
deferred.resolve();
return deferred.promise;
}
function Delete(id) {
var deferred = $q.defer();
var users = getUsers();
for (var i = 0; i < users.length; i++) {
var user = users[i];
if (user.id === id) {
users.splice(i, 1);
break;
}
}
setUsers(users);
deferred.resolve();
return deferred.promise;
}
// private functions
function getUsers() {
if(!localStorage.users){
localStorage.users = JSON.stringify([]);
}
return JSON.parse(localStorage.users);
}
function setUsers(users) {
localStorage.users = JSON.stringify(users);
}
}
})();
AngularJS Login Controller
Back to top
The Login Controller clears the user credentials on load which logs the user out if they were logged in.
The login function exposed by the controller calls the Authentication Service to authenticate the username and password entered into the view.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(function () {
'use strict';
angular
.module('app')
.controller('LoginController', LoginController);
LoginController.$inject = ['$location', 'AuthenticationService', 'FlashService'];
function LoginController($location, AuthenticationService, FlashService) {
var vm = this;
vm.login = login;
(function initController() {
// reset login status
AuthenticationService.ClearCredentials();
})();
function login() {
vm.dataLoading = true;
AuthenticationService.Login(vm.username, vm.password, function (response) {
if (response.success) {
AuthenticationService.SetCredentials(vm.username, vm.password);
$location.path('/');
} else {
FlashService.Error(response.message);
vm.dataLoading = false;
}
});
};
}
})();
AngularJS Login View
Back to top
The Login View contains a small form with the usual fields for username and password, and some validation directives and messages.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
AngularJS Register Controller
Back to top
The Register Controller exposes a single register method which is called from the register view when the form is submitted. The register method then calls the UserService.Create method to save the new user.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
(function () {
'use strict';
angular
.module('app')
.controller('RegisterController', RegisterController);
RegisterController.$inject = ['UserService', '$location', '$rootScope', 'FlashService'];
function RegisterController(UserService, $location, $rootScope, FlashService) {
var vm = this;
vm.register = register;
function register() {
vm.dataLoading = true;
UserService.Create(vm.user)
.then(function (response) {
if (response.success) {
FlashService.Success('Registration successful', true);
$location.path('/login');
} else {
FlashService.Error(response.message);
vm.dataLoading = false;
}
});
}
}
})();
AngularJS Register View
Back to top
The Register View contains just a few fields for user data and some directives for validation.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
AngularJS App.js
Back to top
The part of this file related to authentication is in the run function, when the app starts it checks if there's a cookie containing user credentials meaning the user has already logged in, this is to keep the user logged in after a page refresh.
On each location change there's a check to verify that the user is logged in if trying to access a restricted page, if not they're redirected to the login page.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
(function () {
'use strict';
angular
.module('app', ['ngRoute', 'ngCookies'])
.config(config)
.run(run);
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'home/home.view.html',
controllerAs: 'vm'
})
.when('/login', {
controller: 'LoginController',
templateUrl: 'login/login.view.html',
controllerAs: 'vm'
})
.when('/register', {
controller: 'RegisterController',
templateUrl: 'register/register.view.html',
controllerAs: 'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];
function run($rootScope, $location, $cookieStore, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookieStore.get('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
// redirect to login page if not logged in and trying to access a restricted page
var restrictedPage = $.inArray($location.path(), ['/login', '/register']) === -1;
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
})();
Login
{{vm.error}}
Register
{{vm.error}}
No comments:
Post a Comment
Do you think it could be useful for you? Share your thoughts with us!