I am attempting to prevent navigation in AngularJS based upon the result of an HTTP GET to an authorization endpoint (which ties into my Spring Security architecture, but that's not important to this question).
I have attached the following to a run() block attached to my top-level module:
$rootScope.$on("$locationChangeStart", function(event, newUrl, oldUrl) {
var path = $location.path();
$http.get('/svc/authorize/view?urlPath=' + path).then(response => {
if (response.data.result === "NOT_AUTHORIZED") {
event.preventDefault();
console.log("Prevented unauthorized location change");
$ui.showError("Unable to Navigate to " + newUrl);
}
});
});
(Note: $ui is our service, not an AngularJS or third-party tool).
Unfortunately, due to the asynchronous $http.get(), the page loads before the call completes.
In case it helps, here is an example of our of our route definitions:
$routeProvider.when('/problem', {
templateUrl: '/app/management/problem/problem.tmpl.html',
controller: 'problemCtrl'
});
Can anyone help me? I'm hoping I just made a stupid error in handling the asynchronous call.
One normally uses a resolve
function in the route to prevent unauthorized routes from loading.
$routeProvider.when('/problem', {
templateUrl: '/app/management/problem/problem.tmpl.html',
controller: 'problemCtrl',
resolve: {
authorized: function($http) {
return $http(someUrl).then(function(response) {
var data = response.data;
if (response.data.result === "NOT_AUTHORIZED") {
console.log("Prevented unauthorized location change");
throw "NOT AUTHORIZED";
};
//ELSE
return data;
});
}
}
});
When resolve
functions return promises, the router will wait for the promises to be resolved or rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess
event is fired. If any of the promises are rejected the $routeChangeError
event is fired.
For more information, see
Is there a way to associate the function in authorized with all routes in one single place, instead of modifying each individual route?
The code can be re-factored to use a service:
$routeProvider.when('/problem', {
templateUrl: '/app/management/problem/problem.tmpl.html',
controller: 'problemCtrl',
resolve: { auth: (AuthService,$route) => AuthService.check($route) }
})
Use $route.current.params
to access the proposed new route's parameters.