1
votes

I am trying to implement some security in my app using angular ui-router's resolve function. I've fashioned a solution based on solution #2 in the 2nd answer to this question: Angular ui-router: how to prevent access to a state

It works fine, except that the controller for routes I do not want to allow the user to navigate to is still instantiated. I'm more or less following John Papa's recommendations for Angular, so I have an activate function in each controller. I could double check authentication here, but that would require repetitive work be done to each of my controllers. Also, eliminating the use of $timeout in the authenticate function from the original answer doesn't seem to have an adverse effect.

Here is how I am setting up a route to handle this:

$stateProvider.state('orderqueue', {
                url: "/orderqueue",
                templateUrl: "views/orderqueue.html",
                controller: 'orderQueueController',
                controllerAs: 'orders',
                role: 'Order Admin', 
                resolve: {authenticate: authenticate}
            });

and my authenticate function looks like this:

function authenticate($q,$state,$timeout, UserService) {
            (new UserService()).$getUser().then(
                function(user) {
                    var role = ($state.current.role) ? $state.current.role :$state.current.name ;

                    // alert(role) ;
                    if (user.userName == 'wmfeltman') {
                        return $q.when()    
                    } else
                    {
                        //  $timeout(function() {
                        // This code runs after the authentication promise has been rejected.
                        // Go to the log-in page
                            $state.go('login')
                        // })
                        // Reject the authentication promise to prevent the state from loading
                        return $q.reject()
                    }
                }
            ) 
        }

Is there a way to get resolve to fire before the controller is instantiated? The docs seem to indicate that is how it's supposed to work, but it's not.

1

1 Answers

1
votes

This is quite simple. I see most of the people defines the controller in the state configuration itself.

But you should define the controller in the view itself using ng-controller like this:

views/orderqueue.html

<div ng-controller="orderQueueController as orders">
    <!-- your stuff -->
</div>

Now, you can remove the controller and controllerAs from the state configuration:

$stateProvider.state('`', {
            url: "/orderqueue",
            templateUrl: "views/orderqueue.html",
            role: 'Order Admin', 
            resolve: {authenticate: authenticate}
        });

This way, if your authentication is not successful, the orderqueue will not load, hence, your views/orderqueue.html will not be loaded so the controller will not instantiate (since the controller is initiated with the HTML view).