Defer Angular UI Router $stateChangeStart until server authorization response receieved

前端 未结 4 425
攒了一身酷
攒了一身酷 2020-12-16 15:19

I have an Angular app using UI Router where I\'m trying to validate a user\'s token, if one exists, when the app runs. I am also checking that the user has permission to acc

相关标签:
4条回答
  • 2020-12-16 16:01

    I guess it's too late for answering this question, but I want to comment here for someone who may need a little idea.

    I've tried to do almost same thing for a long time and I stopped doing that. I don't think stateChangeStart listener is reliable to use. I think the best way to do your what you want is decorating $state.go using $provide service. Here is an example:

    /* config your angular app */
    .config(function($provide) {
        $provide.decorator('$state', function($delegate) {
    
            var myState = $delegate;
            // Rename original 'go' method
            myState.originalGo = myState.go;
    
            myState.go = function(toState, toParams, options) {
    
            /*  
             *  Do what you want to do :)
             */
    
            this.originalGo(toState, toParams, options);
        };
    
        return $delegate;
      });
    

    With this approach, you can do whatever you want before $stateChangeStart. I hope it helps.

    0 讨论(0)
  • 2020-12-16 16:01

    You should call $urlRouter.sync() after you have got user data. Also you might want to protect $stateChangeStart by using event.preventDefault() in case when user was not obtained.

    0 讨论(0)
  • 2020-12-16 16:12

    I have found a very good way to make this work properly and not rely on resolve at all in another answer here. Here is the code:

    rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState) {
    
        if (dataService.isInitialized()) {
            proceedAsUsual(); // Do the required actions based on the data you received in the service
        } 
        else {
    
            event.preventDefault();
    
            dataService.intialize().success(function () {
                    $state.go(toState, toParams);
            });
        }
    });
    

    Then you can just remember that your data is already initialized in the service the way you like, e.g.:

    function dataService() {
    
        var initialized = false;
    
        return {
            initialize: initialize,
            isInitialized: isInitialized
        }
    
        function intialize() {
    
            return $http.get(...)
                        .success(function(response) {
                                initialized=true;
                        });
    
        }
    
        function isInitialized() {
            return initialized;
        }
    };
    
    0 讨论(0)
  • 2020-12-16 16:17

    I'd create a function in your Auth service that returns a promise. Later, resolve (authorized) or reject (not authrized) that deferred. Then use it on the resolve property of your route definitions

    $stateProvider.state('stateName',{
        ...
        ...
        resolve: {
             isAuthorized: function(Auth){
                 return Auth.checkAuthorization();
             }
        }
    })
    

    To support subsequent checks you could maintain a promise within the service This might look like:

    myApp.service('Auth',function($http,$q){
        var authStatusDeferred = $q.defer();
        this.checkAuthorization = function(){
            return authStatusDeferred.promise;
        };
    
        this.validateToken = function(user){
            var isValid = false;
            //..do validation stuff
            if(isValid) authStatusDeferred.resolve();
            //Otherwise state change will not happen..            
        };
    
    
    
    });
    

    oh, sorry about no coffee

    0 讨论(0)
提交回复
热议问题