#AngularJS HTTP Digest Authentication
It is an AngularJS module to manage HTTP Digest Authentication in the REST API web apps. It provides functionality to avoid the default form of browsers and use your own. The login and logout are based on digest access authentication and the module helps to manage the user identity in the client side. You can use this module in order to protect your app and authorize the user to navigate inside it.
#Features
- Using your own login and logout
- Interceptor to pass the authorization in all further requests after the login
- Protection for login with a limitation for the number of requests
- Storage for reusing credentials
- Managing identity with
authIdentity
service - Authorization checking as promise with
dgAuthService
- Custom header to parse server information(realm, opaque, domain, etc...)
- Custom callbacks to handle all authorization states(login successful, login error, login required, etc...)
#Installation You can download this by:
- Using bower and running
bower install angular-digest-auth --save
(recommended) - Using npm:
npm install tafax/angular-digest-auth
- Downloading manually the unminified version or the minified production version
After installation, import the module in your app.
var app = angular.module('myApp', ['dgAuth']);
#Dependencies This module depends on angular, angular-state-machine and angular-md5.
#Configuration You need to configure the module as follows.
###Login and logout
You need to provide two URLs on your webserver to simulate the login and
the logout in your app. The signin
URL should return the user identity in a JSON response.
You can access this information via the authIdentity
service.
app.config(['dgAuthServiceProvider', function(dgAuthServiceProvider)
{
dgAuthServiceProvider.setConfig({
login: {
method: 'POST',
url: '/signin'
...
//Other HTTP configurations.
},
logout: {
method: 'POST',
url: '/signout'
...
//Other HTTP configurations.
}
});
}]);
###Header How to configure the header to parse server information.
There is no good non-intrusive method for disabling the custom browser pop-up at the time of writing. See for example these Stack Overflow questions:
- How can I supress the browser's authentication dialog?
- How to prevent browser to invoke basic auth popup and handle 401 error using Jquery?
The solution assumed here is that web server sends a custom alternative to the WWW-Authenticate header in order to avoid the browser opening the default authentication dialog. For example, X-WWW-Authenticate. The value should be the same as it would be for WWW-Authenticate.
app.config(['dgAuthServiceProvider', function(dgAuthServiceProvider)
{
/**
* Specifies the header to look for server information.
* The header you have used in the server side.
*/
dgAuthServiceProvider.setHeader('Your-Header-For-Authentication');
}]);
Note, for more general interoperation, the server could be configured to send this alternative header only if it sees the following header in the request, which is usally sent by default in AJAX calls.
X-Requested-With: XMLHttpRequest
This way, HTTP-Digest works as normal on non-AJAX clients.
AngularJS as of v1.3.0 needs to be instructed to include this as follows:
myAppModule.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
###Limit
Configure the maximum number requests to sign in as in the example below. When the limit is exceeded,
the limit
method in the configured callbacks is invoked. The default limit is 4.
N.B.: the limit includes the initial request to sign in following the invocation of the start
method.
app.config(['dgAuthServiceProvider', function(dgAuthServiceProvider)
{
/**
* Sets the limit to 5 requests.
* 4 requests after the invocation of start method.
*/
dgAuthServiceProvider.setLimit(5);
/**
* Sets the limit of requests to infinite.
*/
dgAuthServiceProvider.setLimit('inf');
}]);
###Callbacks How to configure what happens at the user login and/or logout.
app.config(['dgAuthServiceProvider', function(dgAuthServiceProvider)
{
/**
* You can add the callbacks to manage what happens after
* successful of the login.
*
* Note, replace this example's `someService` with whichever services you need.
*/
dgAuthServiceProvider.callbacks.login.push(['someService', function(someService)
{
return {
successful: function(response)
{
//Your code...
},
error: function(response)
{
//Your code...
},
required: function(response)
{
//Your code...
},
limit: function(response)
{
//Your code...
}
};
}]);
//This is the same for the logout.
/**
* You can add the callbacks to manage what happens after
* successful of the logout.
*
* Note, replace this example's `someService` with whichever services you need.
*/
dgAuthServiceProvider.callbacks.logout.push(['someService', function(someService)
{
return {
successful: function(response)
{
//Your code...
},
error: function(response)
{
//Your code...
}
};
}]);
}]);
###Storage
By default, after the user has logged in, the credentials are stored in sessionStorage
and the module
processes all further requests with these credentials. If you want these user credentials
to persist for more than a single visit to your app, you can specify the localStorage
as default storage.
app.config(['dgAuthServiceProvider', function(dgAuthServiceProvider)
{
/**
* Uses localStorage instead the sessionStorage.
*/
dgAuthServiceProvider.setStorage(localStorage);
}]);
Obviously, if you want to specify your own storage object, you can :).
#Usage
For basic usage, you can launch the start()
when your app runs.
app.run(['dgAuthService', function(dgAuthService)
{
/**
* It tries to sign in. If the service doesn't find
* the credentials stored or the user is not signed in yet,
* the service executes the required function.
*/
dgAuthService.start();
}]);
You should provide the credentials to submit on behalf of the user in your login controller. Then you have to sign in again.
$scope.submit = function(user)
{
dgAuthService.setCredentials(user.username, user.password);
dgAuthService.signin();
};
If the login is successful, all further requests for the API in the domain specified by the server header, will contain the credentials to authorize the user.
#Authorization
You can use this functionality of dgAuthService
to authorize the user to navigate in your app.
app.config(['$routeProvider', function($routeProvider)
{
/**
* Use a variable in resolve to authorize the users.
* The method 'isAuthorized()' returns a promise
* which you can use to authorize the requests.
*/
$routeProvider.when('some/path', {
...
resolve: {
auth: ['dgAuthService', '$q', '$location', function(dgAuthService, $q, $location)
{
var deferred = $q.defer();
dgAuthService.isAuthorized().then(function(authorized)
{
if(authorized)
deferred.resolve();
else
deferred.reject();
},
function(authorized)
{
deferred.reject();
});
return deferred.promise;
}]
}
});
}]);
#License MIT