I'm trying to create an Angular 1 app on top of a SAML secured backend.
When I issue a REST request while not authenticated, I get a response with status 200 and an HTML page that will submit a page to the IDP.
I don't want this 200 response to reach my $http(...).then(function(...){}) method in my services.
So I want to change the 200 to a 401 status code in an HTTP interceptor.
Is that possible?
Any alternatives are welcome.
Ok, I found it:
In the response method, you can use this statement to set the status to 401:
return $q.reject({status: 401, error: 'UNAUTHORIZED'});
Full code-sample:
interceptor = function ($q, $location, $rootScope) {
return {
request: function (config) {
...
return config || $q.when(config);
},
requestError: function (rejection) {
return $q.reject(rejection);
},
response: function (response) {
if (response.status === 200 &&
response.headers()['content-type']==='text/html' &&
response.data.startsWith("<HTML><HEAD><TITLE>SAML HTTP Post Binding</TITLE>")) {
//WE HAVE A SAML AUTH REQUEST
return $q.reject({status: 401, error: 'UNAUTHORIZED'});
}
return response;
},
responseError: function (rejection) {
...
}
};
};
$httpProvider.interceptors.push(interceptor);
Related
My code:
app.factory('myHttpInterceptor', function ($q) {
return {
responseError: function (response) {
console.log("error111111"+JSON.stringify(response));
if(response.status==403)
console.log("403");
else if(response.status==401)
console.log("401");
else
console.log("404");
return $q.reject(response);
}
};
});
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
I'd like to handle status code response. But, it always return 404 code in responseError.
I did a simulation with PHP to return me 403 status => http_response_code(403);
In my chrome inspect shows me 403 code error, but when I see the status code of Interceptor shows me 404 . Why?
Ps: My request is being done using angular jsonp.
Any Help?
I am using the following to show a loading screen whenever I am performing a http request however sometimes if there is an error then it will stay loading (because of the backdrop the app becomes unusable). Rather than hide it on every error checker I was wondering if it is possible to call the timeout after 5 seconds?
.config(function($httpProvider) {
$httpProvider.defaults.timeout = 5000;
$httpProvider.interceptors.push(function($rootScope) {
return {
request: function(config) {
$rootScope.$broadcast('loading:show')
return config
},
response: function(response) {
$rootScope.$broadcast('loading:hide')
return response
}
}
})
})
Following Jess's answer it now looks like this :
.config(function($httpProvider) {
$httpProvider.defaults.timeout = 5000;
$httpProvider.interceptors.push(function($rootScope) {
return {
request: function(config) {
$rootScope.$broadcast('loading:show')
return config
},
response: function(response) {
$rootScope.$broadcast('loading:hide')
return response
},
responseError: function(response) {
$rootScope.$broadcast('loading:hide')
return response
},
requestError: function(response) {
$rootScope.$broadcast('loading:hide')
return response
}
}
})
})
However I cannot seem to be able to put an alert in the requestError to inform the user.
Question
How can I implement an alert to notify the user of the error that has occurred?
try adding responseError and requestError so like this:
responseError: function(responseError) {
$rootScope.$broadcast('loading:hide')
return responseError
and do this again with requestError,
This is from the angular http interceptors docs
requestError: interceptor gets called when a previous interceptor threw an error or resolved with a rejection.
responseError: interceptor gets called when a previous interceptor threw an error or resolved with a rejection.
Edit to answer comment:
so if you want to throw a alert on responseError than a add a $rootScope.$broadcast('response:error')
in the responseError function
then in the controller you want to throw the alert in just do a
$scope.$on('response:error', function(){throw the error here});
you can also do the same for requestError
this works because $broadcast -- dispatches the event downwards to all child scopes
I have simple api and a authorization point
when i request to api i get a 401 if the token is invalid (token loses validity past five minutes).
i know i can intercept 401 for example with
app.factory("HttpErrorInterceptorModule", ["$q", "$rootScope", "$location",
function($q, $rootScope, $location) {
var success = function(response) {
// pass through
return response;
},
error = function(response) {
if(response.status === 401) {
// dostuff
}
return $q.reject(response);
};
return function(httpPromise) {
return httpPromise.then(success, error);
};
}
]).config(["$httpProvider",
function($httpProvider) {
$httpProvider.responseInterceptors.push("HttpErrorInterceptorModule");
}
]);
but i want capture and queue the request and show a login form if is success then change the token (it's a header) and execute request again
You can use $httpInterceptor in slightly another way. If you want to redirect user after login to page where user actually failed you need to cache failed request in some service and then redirect user somewhere after login (I beleive in logic connected to your login).
But you may need to have some test endpoint to protect your controllers from unrestricted access, you might want to use resolve https://thinkster.io/egghead/resolve/
So in this case you will receive error connected with restricted access to proctedted endpoint but not to your page.
To solve this problem I used marker param (or header) to find out where I should redirect user after login.
Here is example of your httpInterceptor.
angular.factory('httpInterceptor', function ($q, $rootScope, $log, someService) {
return {
request: function (config) {
return config || $q.when(config)
},
response: function (response) {
return response || $q.when(response);
},
responseError: function (response) {
if (response.status === 401) {
//here I preserve login page
someService
.setRestrictedPageBeforeLogin(
extractPreservedInfoAboutPage(response)
)
$rootScope.$broadcast('error')
}
return $q.reject(response);
}
};
})
.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
});
angular-http-auth module provides a service that intercepts requests and queques them to re-send them later once a user logs in.
This service fires also these events below, so you could listen to them and decide what to show on screen
event:auth-loginRequired
event:auth-loginCancelled
event:aut-loginConfirmed
Look at the code. It has just a few lines of code
https://github.com/witoldsz/angular-http-auth
I have created http interceptors and attached to my main app as below:
angular.module('app',['ui.router'])
.factory('AuthInterceptor',function($window,$q){
return{
request: function(config){
console.log("config object is");
console.log(config);
if($window.sessionStorage.getItem('token')){
config.headers['x-access-token']= $window.sessionStorage.getItem('token');
}
return config || $q.when(config);
},
response: function(response){
console.log("response object is:");
console.log(response);
if (response['status'] >= 400) {
console.log("Not Authorized.kindly login first");
$state.transitionTo('login');
}
return response || $q.when(response);
}
};
})
.config(function($httpProvider){
$httpProvider.interceptors.push('AuthInterceptor');
});
On the server-side (some express code) I am checking if the user is authorized or not and if not I respond with the following code (only displaying a subset of code to keep things concise):
if(!req.user){
res.send('Not authorized',400);
}
The server code works fine (i can see it in the network tab of the chrome developer tools)
However AuthInterceptor.response() does nto get called.
However do note that the AuthInterceptor.response() does get executed when the response status is 200
So I am confused.. why is it not intercepting 400 statuses ?
If the response status code is outside of the range [200-299], then the responseError interceptor is called.
You need to provide a responseError interceptor:
return {
request: function (config) {...},
responseError: function (rejection) {...}
};
I have an angularjs project. I am just wondering, how to show the user a message, if a requested view/partial is not found (HTTP 404). At the moment, angular starts the request and gets a 404 response including the error-html, but the user doesn't see any change to the website.
Add an $http interceptor (scroll down on this page) for 'responseError'
angular.module("app").config(function($provide, $httpProvider) {
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
'responseError': function(response) {
if (response.status == 404) {
// user hit a 404 -- you can check response.url to see if it matches
// your template directory and act accordingly
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
});