I am using the $http interceptor
to show a login modal when $auth
fails. Here is a brief set-up I have:
$provide.factory('modalWhenLoggedOut', ['$q', '$injector', '$rootScope',
function($q, $injector, $rootScope) {
return {
responseError: function(rejection) {
// $injector.get to fix circular dependency error
var loginModal = $injector.get('LoginModalService');
var $http = $injector.get('$http');
var $state = $injector.get('$state');
// Check for reasons instead of status code
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
// Loop through each rejection reason and redirect
angular.forEach(rejectionReasons, function(value, key) {
if(rejection.data.error === value) {
// Show the login modal
var deferred = $q.defer();
loginModal()
.then(function () {
deferred.resolve( $http(rejection.config) );
})
.catch(function () {
$state.go('index');
deferred.reject(rejection);
});
return deferred.promise;
}
});
return $q.reject(rejection);
}
}
}]);
// Push the new factory onto the $http interceptor array
$httpProvider.interceptors.push('modalWhenLoggedOut');
The above code works fine. But the problem I have is when the api throws multiple auth failure error, the interceptor opens up multiple modals at the same time. Usually in 1 page I might have 2-3 times various services contacting the backend api and when the auth fails, all of those api returns auth failure error during invalid tokens. This interceptor is picking it up as 3 taken_invalid errors and showing 3 login modals 1 on top of each other. How do I prevent this?
How can I make sure the interceptor only shows 1 login modal no matter how many times the auth failure occurred?
My Service Looks something like this:
.service('LoginModalService', ['$modal', '$rootScope',
function($modal, $rootScope) {
function updateRootScope() {
$rootScope.loginProgress = false;
}
if ($rootScope.loginProgress = false) {
return function() {
var instance = $modal.open({
templateUrl: rootPath + 'views/partials/LoginModalTemplate.html',
controller: 'LoginModalCtrl'
})
return instance.result.then(updateRootScope);
};
}
}])
In the service I am trying to use $rootScope.loginProgress
as a switch to figure out if a login modal is opened or not. However, I am not sure how to return an empty promise if modal is already opened (when $rootScope.loginProgress
is true).
To overcome my issue, I am now using
http-auth-interceptor
interceptor and then changing the$rootScope.loginProgress
based on the login modal open status. The consecutive modals that are opened due to multiple 401s will check for this login modal status and then decides to open a modal or not. Usinghttp-auth-interceptor
, I am able to add the switch by watching the'event:auth-loginRequired'
. Here is the code I am using:Where
LoginModalService()
is the service that opens the login modal.