I have a angular application with many $http request and i want redirect the users on the login page if the server session expires (get 401). Does anyone know a solution witch works for all $http without adding .error() on every $http?
It would be better if you could use an http interceptor to redirect all detected 401 errors.
// add an http interceptor via app.config
app.config(function($$httpProvider) {
$httpProvider.interceptors.push('my401Detector');
});
// interceptor logic.
app.factory('my401Detector', function($location, $q) {
return {
responseError: function(response) {
if(response.status === 401) {
$location.path('/login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
};
});
You can use Interceptors to achieve this. From Mean.js source code
angular.module('users').config(['$httpProvider',
function($httpProvider) {
// Set the httpProvider "not authorized" interceptor
$httpProvider.interceptors.push(['$q', '$location', 'Authentication',
function($q, $location, Authentication) {
return {
responseError: function(rejection) {
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.user = null;
// Redirect to signin page
$location.path('signin');
break;
case 403:
// Add unauthorized behaviour
break;
}
return $q.reject(rejection);
}
};
}
]);
}
]);
Related
I have a simple Interceptor in angular that intercepts requests and adds a authorization header. It also intercepts a response error of 401 to know if the request failed because of authorization.
Unfortunately it seems to mess with $resource, because my $resource calls ALWAYS return the success callback and never an error (be it 400 or 500 whatever).
It's definitly the interceptor, because if I remove it, the $resource calls return with the correct callback.
Any ideas on how to fix this behavior?
Here's the interceptors request:
function request(config) {
var token = 'whatever-my-token-is';
if (token) {
config.headers.authorization = token;
}
return config;
}
And the responseError:
function responseError(response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return response;
}
Any help appreciated
I think you need to use a promise to return the error.
adding $q to your Interceptor factory.
like so
$provide.factory('MyHttpInterceptor', function ($q){
...
})
and then have the responseError()
function responseError(response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return $q.reject(response);
}
this link might help also https://djds4rce.wordpress.com/2013/08/13/understanding-angular-http-interceptors/
I'm trying to check before every page load if his session is active, if not, redirect to the login page.
This is my App.js
var app = angular.module('Test', ['ngRoute']);
app.config(function($routeProvider){
$routeProvider
.otherwise({
resolve:
{
"checkUserSession": function($q,$http,$window)
{
console.log('start of the def')
var deffered = $q.defer();
$http.get('/general/php/getCurrentUser.php')
.then(function(result)
{
if(!result)
{
deffered.reject();
$window.location.href = "/";
}
else
{
deffered.resolve();
}
});
$window.location.href = "/";
return deffered.promise;
}
}
})
});
And it won't execute the console.log, the $http.get() or any of the redirects.
It doesn't matter if the promise is resolved or rejected, it looks likes the "checkUserSession" won't ever execute;
Every page includes the angular-route.js script.
Use an interceptor.
In my case I check for the authentication token in local storage but you could use your session logic here.
Start with angular.module(...).config -
.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
$httpProvider.interceptors.push('BearerAuthInterceptor');
...
Then use a service as following:
.factory('BearerAuthInterceptor', function ($q, $injector, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
var tk = $window.localStorage.getItem('token');
if (tk) {
config.headers.Authorization = 'Bearer ' + tk;
}
return config || $q.when(config);
},
response: function (response) {
return response || $q.when(response);
},
responseError: function (rejection) {
if (rejection.status === 401) {
// Redirect to login ui-route
$injector.get('$state').go('login');
}
return $q.reject(rejection);
}
};
})
Some good examples here: http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/
In my application I have a grid which fetches data via HTTP promises. At the moment I can detect errorCallbacks - as below:
myDataPromise.then(function () {
//do stuff
}, function errorCallback(response) {
if (response.statusText === "Not Found") {
//do stuff
}else if(response.statusText === "Internal Server Error"){
//do stuff
}
but say for an SSL error, where chrome fires back "ERR::CONNECTION REFUSED" I cannot pick up on this by reading the string as I can with 404's etc. Really what I want is to display a simple image/text stating that there has been an error in retrieving one's data no matter what it is. So if a http GET fails at all - the user knows. This seems to me like a fairly typical spec but I can't find much online regarding it.
You have to create a interceptor
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
// optional method
'request': function(config) {
// do something on success
return config;
},
// optional method
'requestError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
// optional method
'response': function(response) {
// do something on success
return response;
},
// optional method
'responseError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
// alternatively, register the interceptor via an anonymous factory
$httpProvider.interceptors.push(function($q, dependency1, dependency2) {
return {
'request': function(config) {
// same as above
},
'response': function(response) {
// same as above
}
};
});
The interceptor intercepts all the $http traffic. Even when you are loading templates.
My Question is a bigger and broader version of this question. I want to intercept all http requests issued inside an AngularJS function. Later I need to alter the request URL and than pass it to the server..
How can I do that ? So far I have used $httpProvider and $q to create a interceptor but I am only able to intercept only $http requests not all the requests i.e. if someone clicks on any href link on my page etc. My interceptor code is :-
// register the interceptor as a service
myModule.factory('myHttpInterceptor', function ($q) {
return {
// optional method
'request': function (config) {
// do something on success
console.log("request success");
return config;
},
// optional method
'requestError': function (rejection) {
// do something on error
console.log("Request Error");
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
// optional method
'response': function (response) {
// do something on success
console.log("Response received");
return response;
},
// optional method
'responseError': function (rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
myModule.factory('myInterceptor', ['$log', function ($log) {
$log.debug('$log is here to show you that this is a regular factory with injection');
var myInterceptor = {
};
return myInterceptor;
}]);
myModule.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
Intercepting navigation to other pages is different from intercepting http requests. Maybe what you want is to intercept $location changes.
Have a read through this. You can do it but it depends on where the location changes are to.
http://uiadventures.wordpress.com/2013/09/06/routechange-angularjs/
I'm trying to fire a login modal anytime the server responds with a 401 status code. Based on this guide https://medium.com/opinionated-angularjs/7bbf0346acec I've created a status code interceptor like this.
// intercept http status codes
app.config(function ($httpProvider) {
$httpProvider.interceptors.push(['$injector', function ($injector) {
return $injector.get('AuthInterceptor');
}]);
});
app.factory('AuthInterceptor', function ($rootScope, $q) {
return {
responseError: function (res) {
if (res.status === 401) {
console.log('AuthInterceptor says you are not authorized');
}
if (res.status === 404) {
console.log('AuthInterceptor says this page is not found');
}
return $q.reject(res);
}
};
});
When I try to inject my AuthInterceptor factory with $modal I get a circular dependency error. What is a good practice for triggering a $modal from something like this? The guide that I linked used this AuthInterceptor factory to broadcast 'Auth_events', which were simply constant strings. They didn't show any use of these auth_events beyond broadcasting them so I don't understand how they're suppose to work. In addition to my main question can anyone clarify what these auth events do?
You are getting a circular dependency error since the $modal service has dependency on $http. This is a common problem with $http interceptors that got dependency on $http themselves. Fortunately the remedy is simple: you need to inject $injector into your interceptor and retrieve $model from the injector like so:
app.factory('AuthInterceptor', function ($rootScope, $q, $injector) {
return {
responseError: function (res) {
var $modal = $injector.get('$modal');
if (res.status === 401) {
//you can use $modal here...
console.log('AuthInterceptor says you are not authorized');
}
if (res.status === 404) {
console.log('AuthInterceptor says this page is not found');
}
return $q.reject(res);
}
};
});