Authentication is the process of identifying whether a client or a user is someone he/she claimed to be. Generally, the authentication process enables certain extra functionality for the user. Web applications make use of HTTP protocols for transactions between the server and the client. This HTTP protocol supports authentication as a means of providing access to the server’s secured resources.
The most common authentication method used in HTTP is “Basic” authentication. This mechanism is the process of passing user credentials in a form of a Base64 encoded string in the authorization header of an HTTP request. The credentials are then verified and the response is sent to the client. If credentials are wrong then the unauthorized status response is sent to the client.
In this application, we will demonstrate a combined Login and Registration Application in AngularJS. This example makes use of the HTML5 web storage feature i.e. we will use local storage for storing the user details locally in the user’s browser/computer, permanently. It is similar to cookies but the data stored on local storage is not sent to the web server like cookies where data is sent to the server with every request. Unlike cookies, it can store any amount of data. Hence this approach is faster and secure. It uses the “localStorage” object to store the data. Form validation using attributes and ngMessages is already explained and covered in the previous articles.
Other Web Application Examples:
- Simple Login form in AngularJS with an example
- Registration form in AngularJS with an example
- Login tutorial in Java
Following are the Requirement details for this application are as follows. Combined Login and Registration Application
- Login page
- Username
- Password
- Login and Register buttons
- Registration page
- First Name
- Last Name
- Username
- Password
- Register and Cancel buttons
- Home page
- It should display the user’s full name with a welcome message.
- It should display all the registered users in an appropriate format.
- Logout and View-Users buttons
- Functionality
- When the application is run, the Login page will appear.
- When the user enters the details and tries to log in, his credentials will be So before login user needs to register themselves using the Register button on the login page. Once he is done with registration he can log in with these details.
- If the user logs in successfully, he will be taken to the home page.
Following are the filenames used in this application.
The index.html gets loaded initially. In the index.html, we have registered angular scripts, bootstrap styling scripts, and all the controller javascript files. Also, we have an ng-view for loading each view page according to routing action.
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Basic HTTP Authentication Example</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="jumbotron">
<div class="container">
<div class="header">AngularJS Basic HTTP Authentication Example</div>
<div class="col-sm-8 col-sm-offset-2">
<div ng-view></div>
</div>
</div>
</div>
<script src="//code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="//code.angularjs.org/1.6.0/angular.min.js"></script>
<script src="//code.angularjs.org/1.6.0/angular-route.min.js"></script>
<script src="//code.angularjs.org/1.6.0/angular-cookies.min.js"></script>
<script src="app.js"></script>
<script src="homeController.js"></script>
<script src="loginController.js"></script>
<script src="registerController.js"></script>
<script src="userService.svc.js"></script>
<script src="authenticationService.svc.js"></script>
</body>
</html>
Now, we will create our application module. In the below code, app.js we have created an app module and invoked ngRoute for routing mechanism and ngCookies for storing user credentials in cookies. The config() function is used for configuring routes using $routeProvider. Run() function is used for the initial logic whenever the application is run where we are just clearing the console logs.
app.js
(
function () {
'use strict';
angular
.module('app', ['ngRoute', 'ngCookies'])
.config(config)
.run(run);
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
controller: 'LoginController',
templateUrl: 'login.html',
controllerAs: 'vm'
})
.when('/home', {
controller: 'HomeController',
templateUrl: 'home.html',
controllerAs: 'vm',
})
.when('/register', {
controller: 'RegisterController',
templateUrl: 'register.html',
controllerAs: 'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope'];
function run(){
console.clear();
}
})();
If the user does not have an existing account to log-in, he/she must create an account by registering to get the credentials.
register.html.
<div class="col-md-6 col-md-offset-3">
<h4 style="text-align:center;color:blue">Register</h4>
<form name="form" ng-submit="vm.register()" role="form">
<div class="form-group" ng-class="{ 'has-error': form.firstName.$dirty && form.firstName.$error.required }">
<label for="username">First name</label>
<input type="text" name="firstName" id="firstName" class="form-control" ng-model="vm.user.firstName" required />
<span ng-show="form.firstName.$dirty && form.firstName.$error.required" class="help-block">First name is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.lastName.$dirty && form.lastName.$error.required }">
<label for="username">Last name</label>
<input type="text" name="lastName" id="Text1" class="form-control" ng-model="vm.user.lastName" required />
<span ng-show="form.lastName.$dirty && form.lastName.$error.required" class="help-block">Last name is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.username.$dirty && form.username.$error.required }">
<label for="username">Username</label>
<input type="text" name="username" id="username" class="form-control" ng-model="vm.user.username" required />
<span ng-show="form.username.$dirty && form.username.$error.required" class="help-block">Username is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.password.$dirty && form.password.$error.required }">
<label for="password">Password</label>
<input type="password" name="password" id="password" class="form-control" ng-model="vm.user.password" required />
<span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Password is required</span>
</div>
<div class="form-actions">
<button type="submit" ng-disabled="form.$invalid || vm.dataLoading" class="btn btn-primary">Register</button>
<img ng-if="vm.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgA" /> <!-- truncated line -->
<a href="#!/" class="btn btn-link">Cancel</a>
</div>
</form>
</div>
From the register.html, the register() function gets called on Register button event click. In this method, we are taking user inputs and passing them to create() function in UserSrvice. It will respond back with either success or failure and the message is shown to the user in UI.
registerController.js
(function () {
'use strict';
angular
.module('app')
.controller('RegisterController', RegisterController);
RegisterController.$inject = ['UserService', '$location'];
function RegisterController(UserService, $location) {
var vm = this;
vm.dataLoading = false;
vm.register = register;
function register() {
vm.dataLoading = true;
UserService.create(vm.user)
.then(function (response) {
if (response.success) {
alert('Registration successful');
$location.path('/');
} else {
alert(response.message);
vm.dataLoading = false;
}
});
}
}
})();
Next, we will build the login.html. The login form basically contains a placeholder to key-in username and password.
login.html
<div class="col-md-6 col-md-offset-3">
<h4 style="text-align:center;color:blue">Login</h4>
<form name="form" ng-submit="vm.login()" role="form">
<div class="form-group" ng-class="{ 'has-error': form.username.$dirty && form.username.$error.required }">
<label for="username">Username</label>
<input type="text" name="username" id="username" class="form-control" ng-model="vm.username" required />
<span ng-show="form.username.$dirty && form.username.$error.required" class="help-block">Username is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': form.password.$dirty && form.password.$error.required }">
<label for="password">Password</label>
<input type="password" name="password" id="password" class="form-control" ng-model="vm.password" required />
<span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Password is required</span>
</div>
<div class="form-actions" layout="row">
<button type="submit" ng-disabled="form.$invalid || vm.dataLoading" class="btn btn-primary">Login</button>
<img ng-if="vm.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///" /> <!-- truncated line -->
<span style="float:right">Not a member?<a href="#!/register" class="btn btn-link">Register</a></span>
</div>
</form>
</div>
When a user submits his information from the login form, the information is passed to the controller javascript, loginController.js file. In this code, we are adding a reference for the AuthenticationService to authenticate the user credentials when login() function is invoked and the $location is used for navigating between pages after the user successfully logs-in into the application. If a user fails to log in a popup with is failure message is displayed.
loginController.js.
(function () {
'use strict';
angular
.module('app')
.controller('LoginController', LoginController);
LoginController.$inject = ['$location','AuthenticationService'];
function LoginController( $location, AuthenticationService) {
var vm = this;
vm.login = login;
(function initController() {
// reset login status
AuthenticationService.ClearCredentials();
})();
function login() {
console.log("login method executing");
vm.dataLoading = true;
AuthenticationService.Login(vm.username, vm.password, function (response) {
if (response.success) {
AuthenticationService.SetCredentials(vm.username, vm.password);
$location.path('/home');
} else {
alert(response.message);
vm.dataLoading = false;
}
});
}
}
})();
Next, we will go through the authenticationService.js where we will verify the user credentials. There are 3 functions in this service.
- Login: This function is invoked from login controller when login button is clicked from UI. Here, the user credentials are verified against stored values and a success or failure response is returned.
- SetCredentials: This function has the logic for storing the user credentials in a rootScope object and as well as in cookies in a form of Base64 encoded string. The same encoded string is even passed in the header of HTTP protocol so that credentials are passed in every request. This function is called from login controller when user’s credentials are verified on login event and are correct.
- ClearCredentials: It will clear stored credentials from the rootScope, cookies and from the header of the HTTP protocol. This function is called when the login page is loaded.
authenticationService.js
(function () {
'use strict';
angular
.module('app')
.factory('AuthenticationService', AuthenticationService);
AuthenticationService.$inject = ['$http', '$cookies', '$rootScope', '$timeout', 'UserService'];
function AuthenticationService($http, $cookies, $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
}
};
// set default auth header for http requests
$http.defaults.headers.common['Authorization'] = 'Basic ' + authdata;
// store user details in globals cookie that keeps user logged in for 1 week (or until they logout)
var cookieExp = new Date();
cookieExp.setDate(cookieExp.getDate() + 7);
$cookies.putObject('globals', $rootScope.globals, { expires: cookieExp });
}
function ClearCredentials() {
$rootScope.globals = {};
$cookies.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;
}
};
})();
Next, we will implement the user service page. In this service, we store the user details (the input values taken from the registration page) in the localStorage object and fetch from the same. Here, we have 3 public functions and 2 private functions. The public functions are:
- get: For fetching all users. This is called from the home page to display all users.
- getByUsername: Fetches a user object for the passed username.
- create: Makes an entry for a new user. Before making an entry it will check for the user existence by username. If it does not exist, it will create a new entry. In case of failures, it sends a response as false.
userService.svc.js
(function () {
'use strict';
angular.module("app")
.service("UserService" , UserService);
UserService.$inject = ['$timeout', '$filter', '$q'];
function UserService($timeout, $filter, $q){
var service = {};
service.get = get;
service.getByUsername = getByUsername;
service.create = create;
return service;
function get(){
var deferred = $q.defer();
deferred.resolve(getUsers());
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 exists' });
} 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);
createUser(users);
deferred.resolve({ success: true });
}
});
}, 1000);
return deferred.promise;
}
function getUsers(){
if(!localStorage.users){
localStorage.users = JSON.stringify([]);
}
return JSON.parse(localStorage.users);
}
function createUser(users){
localStorage.users = JSON.stringify(users);
}
}
})();
When the user logs in successfully, he is taken to the home.html. In this code, a div tag is used to display a welcome message with the user full name and a table to display all the registered users.
home.html
<div class="col-md-6 col-md-offset-3">
<h2 style="text-align:center;color:blue">Home</h2>
<div align="right"><a href="#!/">Logout</a></div>
<h3>Hi {{vm.currentUser.firstName + " " + vm.currentUser.lastName}}</h3>
<div>Welcome.. You're logged in successfuly!!
<br/>To view all the users please click on below link.</div>
<div align="right">
<a href="" ng-click="vm.showUsers = !vm.showUsers">View Users</a>
</div>
<div ng-if="vm.showUsers">
<h4>Registered Users:</h4>
<table class = "table table-striped table-bordered table-hover">
<thead>
<tr class = "info">
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr ng-repeat = "user in vm.allUsers track by $index">
<td>{{ user.firstName }}</td>
<td>{{ user.lastName }}</td>
<td>{{ user.username }}</td>
</tr>
</tbody>
</table>
</div>
</div>
To get the currently logged in user details, the function loadCurrentUser() is used. To display all the user details, we use loadAllUsers() function.
homeController.js.
(function () {
'use strict';
angular
.module('app')
.controller('HomeController', HomeController);
HomeController.$inject = ['UserService', '$rootScope'];
function HomeController(UserService, $rootScope) {
var vm = this;
vm.showUsers = false;
vm.currentUser = null;
vm.allUsers = [];
initController();
function initController() {
loadCurrentUser();
loadAllUsers();
}
function loadCurrentUser() {
UserService.getByUsername($rootScope.globals.currentUser.username)
.then(function (user) {
vm.currentUser = user;
});
}
function loadAllUsers() {
UserService.get()
.then(function (users) {
vm.allUsers = users;
});
}
}
})();
Next, to make UI attractive, we need to apply a stylesheet to it. Following code contains the Style.css.
.header{
text-align:center;
color:black;
font-weight:bold;
font-size:16px;
margin:0 0 25px 0;
}
Let us run our application and see its output.
- Initially, when our application gets loaded, it looks like the below.
- If the user is using this application for the first time, he needs to register himself. Without doing this he can not login to the application with any other credentials. Click on the Register link to continue with the registration.
- You need to enter all the details and click on the Register button which will save all the entered details in the local storage and it will display a success notification.
- If the entered username already exists in the system, it displays a notification message “Username “sample” already exists”.
- On successful login, it will take you to the home page. Please take a look at the below.
- All the registered users are displayed on the home page by clicking the View Users button.
- The logout button facilitates to log-out from the current session and the user will be redirected to the login page.
- If the user credentials are wrong, it displays a failure message.
hii…I m facing a issue after after registration while clicking a login.. it is not showing home page..plzz help me
Do you see any error there Nikita?