angularjsngroute

Preventing Unauthorized URL Changes in AngularJS Based on HTTP Request


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.