I have the following factory in my Angular App. It is used to add bearer token information, to the header of all my outgoing request with $resource. It works as expected.
But i have implemented some external calls, which should not be added with the bearer token. How do i implement a check, so i can control what calls are getting intercepted and which are not?
My code:
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function(config) {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
// error handler
}
};
}
])
Add the authInterceptor:
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}])
Factory for a resource:
myApp.factory('Random', function ($resource) {
return $resource('domain.com', { }, {
update: {
method: 'PUT'
}
});
});
Call the resource:
Random.query({ });
Any ideas?
There are many ways, for example, you can do something in the request object,
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function(config) {
if(config.url !== 'external url') {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
}
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
// error handler
}
};
}
])
with that conditional, you will skip unwanted url mods.
check out the doc as well,
https://docs.angularjs.org/api/ng/service/$http#usage
you can even create a key for all calls, that switches the interception on / off.
Related
I have a login function that works. But, when the user enters an invalid credential, i of course want to display this. But I cant seem to catch the error.
This is my code that works;
function userAccount($resource) {
return {
login: $resource("/Token", null,
{
'loginUser': {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
transformRequest: function (data, headersGetter) {
var str = [];
for (var d in data)
str.push(encodeURIComponent(d) + "=" +
encodeURIComponent(data[d]));
return str.join("&");
}
}
})
}
}
vm.login = function () {
vm.userData.grant_type = "password";
vm.userData.userName = vm.userData.email;
userAccount.login.loginUser(vm.userData,
function (data) {
//login
},
function (response) {
//run this if error (code 400 or similar error)
});
}
});
What do I need to change, to make sure the last bit is run, when to request fails?
EDIT
I found this in the code, and it looks like that is intercepting the error - but how do i get it to, work with my login function, so i can get an error displayed to the user?
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function (config) {
if (currentUser.getProfile().token) {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
}
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
// error handler
}
};
}
])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}])
When i remove the last 3 lines, and thereby disabling the interceptor, it works, and the error is caught and showed to the user.
So how to make these work together? :)
You need to return the rejection or error object back to the login user requset object like this
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function (config) {
if (currentUser.getProfile().token) {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
}
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
if(ableToREsolve()){
return customRejection
}
return $q.reject(rejection);
}
};
}
])
This in turn will be caught in :
responseError: function(rejection) {
// Show in modal or alert
}
For better understanding I suggest to read on interceptors. Interceptors are of four types:
Request
2.Request Error
3.Response
4.Response Error
In simple words, Interceptors get called before actual
request is passed on to server
response is delivered to client
So in your case error needs to be returned from interceptor in able to be caught by your request object error function.
request
I have make a POST request to an API and they have basic authentication, how can I tell angular $http POST service to pass my credential while making the post requestion?
You can add auth interceptor as follows
angular.module('interceptors.authInterceptor',[])
.factory('authInterceptor', ['$q', function ( $q) {
return {
request: function (config) {
config.headers = config.headers || {};
config.headers['Authorization'] = 'Bearer ' + YOUR_AUTH_TOKEN;
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(rejection) {
}
};
}])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}]);
I am using $http interceptor to config my http headers.
app.factory('httpRequestInterceptor', ['$q', '$location', 'localStorageService', function ($q, $location, localStorageService) {
var _request = function (config) {
config.headers = config.header || {};
var authData = localStorageService.get('authData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
var _responseError = function (rejection) {
if (rejection.status == 401) {
$location.path('/login');
}
return $q.reject(rejection);
}
return {
request: _request,
responseError: _responseError
}
}]);
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
}]);
Without using $http interceptor (which means if I comment
$httpProvider.interceptors.push('httpRequestInterceptor')
), my post method words fine.
$http.post(RoutePrefix + "api/accounts/create", dataToSend, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function (data, status, headers, config) {
console.log("succes!");
}).error(function (data, status, headers, config) {
console.log("Error!");
});
But if I use $http interceptor,
I will get 415(Unsupported media error).
message: "The request entity's media type 'text/plain' is not supported for this resource."
exceptionMessage: "No MediaTypeFormatter is available to read an object of type 'CreateUserViewModel' from content with media type 'text/plain'."
exceptionType: "System.Net.Http.UnsupportedMediaTypeException"
Any solution or suggestion about my problem? Thanks in advance.
On the line:
config.headers = config.header || {}
The right part is missing an ending s character after header word. Therefore config.headers gets initialised to {} because config.header is undefined.
But, even if it were written config.headers = config.headers || {}, I think it's not necessary at all nor wouldn't have any sense.
I have the following code for token based authentication with my backend api in AngularJS:
$httpProvider.interceptors.push(['$q', '$location', '$localStorage', function($q, $location, $localStorage) {
return {
'request': function (config) {
config.headers = config.headers || {};
if ($localStorage.token) {
config.headers.Authorization = 'Bearer ' + $localStorage.token;
}
return config;
},
'responseError': function(response) {
if(response.status === 401 || response.status === 403) {
$location.path('/signin');
}
return $q.reject(response);
}
};
}]);
This sets the "Authorization" header to my token.
How do I have to modify my code to use an URL parameter (named "access_token") instead of an header?
You need to use the argument params – {Object.} of config object:
params – {Object.<string|Object>} – Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be JSONified.
AngularJS reference guide
$httpProvider.interceptors.push(['$q', '$location', '$localStorage', function($q, $location, $localStorage) {
return {
'request': function (config) {
//config.headers = config.headers || {};
config.params = config.params || {};
if ($localStorage.token) {
config.params.access_token = $localStorage.token;
//config.headers.Authorization = 'Bearer ' + $localStorage.token;
}
return config;
},
'responseError': function(response) {
if(response.status === 401 || response.status === 403) {
$location.path('/signin');
}
return $q.reject(response);
}
};
}]);
ExpressJS is sending the following response...
res.send('ItemUploaded');
I'm trying to get AngularJS to see this response via an Interceptor and perform a redirect. Does anyone have sample code where Angular catches a server response (such as my "ItemUploaded") and performs a redirect to a partial (via $location)?
This works fine. I have used it in my application.
var interceptor = function ($q, $location) {
return {
request: function (config) {//req
console.log(config);
return config;
},
response: function (result) {//res
console.log('Repos:');
console.log(result.status);
return result;
},
responseError: function (rejection) {//error
console.log('Failed with', rejection.status, 'status');
if (rejection.status == 403) {
$location.url('/dashboard');
}
return $q.reject(rejection);
}
}
};
module.config(function ($httpProvider) {
$httpProvider.interceptors.push(interceptor);
});
Here is the factory for the interceptor:
.factory('InterceptorService',['$q', '$location', function( $q, $location, $http){
var InterceptorServiceFactory = {};
var _request = function(config){
//success logic here
return config;
}
var _responseError = function(rejection) {
//error here. for example server respond with 401
return $q.reject(rejection);
}
InterceptorServiceFactory.request = _request;
InterceptorServiceFactory.responseError = _responseError;
return InterceptorServiceFactory;
}]);
then register the interceptor:
.config(["$httpProvider", function ($httpProvider) {
$httpProvider.interceptors.push('InterceptorService');
}]);
Every request coming will be passed here.
You can implement a interceptor factory which will redirect if it gets a matching result.
angular
.module('app')
.factory("httpinterceptor", ["$location",
function(location) {
return {
'response': function(response) {
if (response.data === "ItemUploaded") {
location.path("/ItemUploaded")
}
}
}
}
]);