Preventing Unauthorized URL Changes in AngularJS Based on HTTP Request

Issue

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.

Solution

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.

Answered By – georgeawg

Answer Checked By – David Goodson (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.