Redirect angular path but hold server data - angularjs

Sorry if this could be a newbie question.
So this frontend app has an interceptor.
For each request to server, the interceptor will be the first to manage the server response:
service.responseError = function (response) {
};
Now, if the server returns other status then 200, I want to redirect to another frontend path:
service.responseError = function (response) {
if (response.status === 419){
$location.path(handleError);
return;
}
return response;
};
handleError is an angular controller. Can this controller come over the server response?

Ok, doing this in interceptor:
$rootScope.interceptorData = response.data;
And then in controller injecting $rootScope and reading from it, solves it.

Related

Simple interceptor that will fetch all requests and add the jwt token to its authorization header

In my efforts to setup login required to protected pages and reroute to the login page if not authorized, while using Django REST Framework and DRF-JWT, I am trying to go through the following tutorial:
https://www.octobot.io/blog/2016-11-11-json-web-token-jwt-authentication-in-a-djangoangularjs-web-app/
I am not sure what this looks like in step 3 of the front-end section.
// Add a simple interceptor that will fetch all requests and add the jwt token to its authorization header.
Can someone provide an example?
Also, my original post regarding the issues I am having setting this up in general.
Trying to get login required to work when trying to access protected pages
Thanks!
The interceptors are service factories that are registered with the
$httpProvider by adding them to the $httpProvider.interceptors array.
The factory is called and injected with dependencies (if specified)
and returns the interceptor.
The basic idea behind intercepter is that it will be called before each $http request and you could use a service to check if user is logged in and add a token or anything else that needs to be added into the header.You could also add some logic for response for each $http request, like handling the response based on status code.
Here is how you can use it in angular for adding the access token for each http request.
angular.module('myapp')
.run(['$rootScope', '$injector', function($rootScope,$injector) {
$injector.get("$http").defaults.transformRequest = function(data, headersGetter) {
if (sessionService.isLogged()) {
headersGetter()['Authorization'] = "Bearer " + sessionService.getAccessToken();
}
if (data) {
return angular.toJson(data);
}
};
});
Here is how you can use response intercepter:
angular.module('myapp')
.factory('authHttpResponseInterceptor', function($q, $location, sessionService, $http) {
return {
response: function(response) {
//some logic here
return response || $q.when(response);
},
responseError: function(rejection) {
if (rejection.status === 401) {
//some logic here
}
return $q.reject(rejection);
}
}
});

angularjs http interceptor to show error on loaded location path

I have an application for which I created an interceptor to handle token expirations after 15 minute inactivity, it successfully redirects to the login page after a token has expired, but Im not able to show the error after redirecting to the login page.
My question is, how can I show the user the token expired error on the login page, after the interceptor has redirected the app to that page.
Heres my redirector:
app
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q, $location, LoopBackAuth) {
return {
responseError: function(rejection) {
if (rejection.status == 401) {
//Now clearing the loopback values from client browser for safe logout...
LoopBackAuth.clearUser();
LoopBackAuth.clearStorage();
$location.path("/login");
}
return $q.reject(rejection);
}
};
})
}])
.config(function(LoopBackResourceProvider) {    
LoopBackResourceProvider.setAuthHeader('X-Access-Token');
})
Finally and thanks to #forrestmid to point me in the right direction this is what I ended up doing.
on the http interceptor just added:
$location.path("/login").search({error: 'invalid_token'});
and then on the controller just had to do:
var queryString = $location.search();
$scope.errors = {};
if (queryString && queryString.error) {
$scope.errors = {
'invalid_token': {
code: 'invalid_token'
}
}
}
now on the template I already have logic to handle the error object so now it works fine :)
Referencing this post in regards to injecting the $state service into an HTTP interceptor:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q, $injector, LoopBackAuth) {
return {
responseError: function(rejection) {
if (rejection.status == 401) {
//Now clearing the loopback values from client browser for safe logout...
LoopBackAuth.clearUser();
LoopBackAuth.clearStorage();
$injector.get('$state').go('app.login', {error: 'Token expired.'});
}
return $q.reject(rejection);
}
};
})
}]);
Assuming that you're using ui.router:
app.config(function($stateProvider){
$stateProvider
.state("app",{abstract: true})
.state("app.login", {
url: "/login",
params: {error: ""}
});
});
By default there will be no error when transitioning to the app.login state, but when there is a param error set to whatever, it can display the error. This will be in the $stateParams.error variable on your login page.
Let me know if I botched any of that code since I didn't test it. The line I think you want is the $injector line.

how to have angularJS post data to MVC controller which redirects to a view

I am posting some data to an MVC action method using AngularJS. This action method will either show its backing view or redirect to another page. Currently all that is happening is the data is getting posted but the redirect is not happening via MVC. I am getting this done using angular's window.location method. I want to know if there is a better way or if I need to post differently using Angular.
On page A I have angular scripts posting data to page B like below:
serviceDataFactory.POST('http://localhost:1234/home/B', someData, pageConfig).then(function () {
//on success
window.location = 'http://localhost:1234/home/Index';
},
function() {
//on error
window.location = 'http://localhost:1234/home/B';
});
This is my service factory
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
var d = $q.defer();
$http({
method: 'POST',
url: url,
data: postData,
config: conf
}).success(function(data) {
d.resolve(data);
}).error(function(error) {
d.reject(error);
});
return d.promise;
}
return service;
}
);
On Page B I want to redirect to another page. This is my page B in MVC
[HttpPost]
public ActionResult B(string someData)
{
//recieve string someData and perform some logic based on it
.
.
.
if(boolCondition)
return RedirectToAction("Index", "Home");
else
return View();
}
Here once Angular posts to the action method B, it executes all the code all the way till the if(boolCondition) statement. Since I am unable to have that redirect affected via MVC, I do that in Angular itself using the success or error block that the promise returns to.
I want to know if there is a better way to do this or if I am doing something wrong here or if this is the only acceptable way. How do I get angular to hand-off to the MVC action method and let further redirects continue from there only?
You should not use the .success() / .error() pattern with $http, because this has been deprecated. Instead, use then() with two arguments, the first argument being the success function and the second being the error function.
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
You do not need to promisify the result of $http, because $http returns a promise. Just return $http from your service.
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
return $http({
method: 'POST',
url: url,
data: postData,
config: conf
});
}
return service;
});
Your Page A controller will work the same as before with this new simplified code. At the server, be sure to emit a 500 http status code in cases where you want to trigger the
function() {
//on error
window.location = 'http://localhost:1234/home/B';
}
to run. The 500 in the headers of the response will cause the AngularJS promise to run the second function in your controller.

Attach parameter(s) with $http Angularjs

I have $http request in Angularjs project.
$http.get('http://api.domain.com/index?abc=123')
.success(function (data) {
console.log('Success!');
})
.error(function (data) {
console.log('False');
});
Now, i want add token to each $http request, like
$http.get('http://api.domain.com/index?abc=123&token=456')...
I know a way to send token via header:
$http.defaults.headers.common['X-AUTH-TOKEN'] = token;
But i want use it as parameter, can i?
Regards!
You can use the params option in config of $http
var myHttpConfig = {
params: {
abc: 123,
token: 456
}
}
$http.get( url, myHttpCongig).then(function...
If you want an app wide approach to send the same params use $http interceptors
Note that success and error are now deprecated per the $http docs

Angular : intercept specific request with $resource

I'm new to Angular, and am working on an interceptor. I created an angular factory to get some data from an API like that :
app.factory('Connection',['$resource',function($resource) {
return $resource('url',{param1: '1',param2: '55'},);
}]);
I also created the interceptor which looks like that :
app.factory('connectionInterceptor', function($q,$location) {
var connectionInterceptor = {
response: // code here
responseError: // code here
};
return connectionInterceptor;
});
The interceptor works well. But it intercepts every http request I do, and I'd like to make it work for a specific $resource. I read in angular $resource doc that there is a way to make it by adding an interceptor action/param to $resource. So I tried :
app.factory('Connection',['$resource',function($resource) {
return $resource('http://localhost:8080/api/login',{user: '1',password: '55'}, {},
query: {
method : 'GET',
interceptor : 'connectionInterceptor'
}
});
}]);
which didn't work. The thrown error is : Error in resource configuration for action query. Expected response to contain an object but got an array.
What did I miss ?
As you said, interceptors are globally set. I had to add a test to my response to check the $resource URL and add some specific treatment.
module.factory('interceptor', function() {
var interceptor = {
response: function(response) {
if (response.config.url.startsWith('my url')) {
// some treatment
}
else
// other treatment
return response;
}
return connectionInterceptor;
});

Resources