推迟Angular UI路由器$ stateChangeStart,直到收到服务器授权响应

时间:2014-01-25 20:11:06

标签: javascript angularjs coffeescript authorization angular-ui-router

我有一个使用UI路由器的Angular应用程序,我试图在应用程序运行时验证用户的令牌(如果存在)。我还检查用户是否有权访问某些路线。问题是在我从授权端点收到响应之前$stateChangeStart正在运行。这是一些代码(下面带有js的coffeescript) - 这都在我的run块中。

app.run(($rootScope, $state, $stateParams, $log, Auth) ->

  currentState = 'home'

  $rootScope.$state = $state

  # read a cookie if cookie exists
  if Auth.setAuthenticationToken()
    # hit api endpoint to validate token
    Auth.validateToken (user) ->
      # route to current state
      # this returns after $stateChangeStart runs below
      $state.go(currentState)

  $rootScope.$on '$stateChangeStart', (event, toState, toParams, fromState, fromParams) ->

    currentState = toState.name

    Auth.setAuthenticationToken()

    $rootScope.error = null

    # compare users access permissions with incoming route's access level
    if (!Auth.authorize toState.data.access, Auth.user)
      event.preventDefault()
      $rootScope.error = "Sorry, you haven't provided the required credentials."
      $log.warn $rootScope.error
)

我的问题是如何在返回auth端点的响应后才能运行$stateChangeStart。这只需要第一次发生。每次后续状态更改都可以在不命中auth端点的情况下完成。

4 个答案:

答案 0 :(得分:6)

我会在Auth服务中创建一个返回承诺的函数。之后,解决(授权)或拒绝(未授权)延期。然后在路径定义的resolve属性

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

为了支持后续检查,您可以在服务中维护承诺。这可能如下所示:

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..            
    };



});

哦,抱歉没有咖啡

答案 1 :(得分:1)

获得用户数据后,您应该致电$urlRouter.sync()。另外,如果未获得用户,您可能希望使用$stateChangeStart来保护event.preventDefault()

答案 2 :(得分:1)

我想回答这个问题已经太晚了,但我想在这里评论可能需要一点想法的人。

我试图长时间做同样的事情而且我不再那样做了。我不认为stateChangeStart听众可靠使用。 我认为使用$state.go服务来装饰$provide的最佳方式就是使用/* 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; }); 服务。这是一个例子:

$stateChangeStart

通过这种方法,您可以在String sqlStatement = "SELECT StartDate, EndDate FROM Booking between " + startD + ", " + endD;之前做任何您想做的事情。 我希望它有所帮助。

答案 3 :(得分:1)

我找到了一种非常好的方法来使这项工作正常,而不是完全依赖于另一种答案中的决心here。这是代码:

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);
        });
    }
});

然后您可以记住,您的数据已经按照您喜欢的方式在服务中初始化,例如:

function dataService() {

    var initialized = false;

    return {
        initialize: initialize,
        isInitialized: isInitialized
    }

    function intialize() {

        return $http.get(...)
                    .success(function(response) {
                            initialized=true;
                    });

    }

    function isInitialized() {
        return initialized;
    }
};