簡體   English   中英

$ state.go不在諾言工作

[英]$state.go not working from promise

我正在嘗試實施基本安全檢查,以阻止用戶訪問某些狀態,具體取決於他們的權限集:

'use strict';

var autoExecApp = angular.module("myApp", ['ui.router']);

autoExecApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
    $stateProvider
        .state('index', {
            url: '/index',
            templateUrl: 'partials/index.html'
        })
        .state('permission', {
            url: '/permission',
            templateUrl: 'partials/permissions.html'
        });
}]);

autoExecApp.run(['$rootScope', '$state', '$userRoles', function($rootScope, $state, $userRoles) {

    $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {

        event.preventDefault(); // prevent page from being loaded anyway
        $userRoles.hasPermissions(toState.name).then(function(data) {
            var result = data === "true";
            if (!result) {
                $state.go('permission');
            }
            else {
                $state.go(toState.name, toParams ,{notify:false});
            }
        });
    });
}]);

現在問題圍繞着我的狀態變化發生在承諾內部的事實。 我很樂意讓它同步 - 因為它確實應該在這種情況下,但我很困惑為什么它不是異步工作。

如果我在promise中移動event.preventDefault() ,它就可以了。 但是狀態改變分為兩步。 首先,它將始終轉到原始頁面,然后在轉換到“已阻止”頁面后很快(如果它被阻止)。 我收集這是因為它從$ on成功返回一次並更新狀態,然后在從promise返回時再次更新它。

如果承諾是你如何看待它,狀態將不會改變。 一切似乎都有效,但頁面不會更新視圖。 我不確定為什么會這樣。 出於某種原因,如果未阻止事件,則稍后的狀態更改將起作用。 但是,如果它被阻止並且從返回的promise中調用$ state.go,則更新$ state似乎為時已晚。

編輯:我使用廣播解決方案取得了成功,這就是它的樣子:

event.preventDefault();
$state.go(toState.name, toParams, {notify: false}).then(function() {
     // line 907 state.js
     $rootScope.$broadcast('$stateChangeSuccess', toState, toParams, fromState, fromParams);
});

顯然由於它是一個承諾,preventDefault(); 從自然射擊中抑制這個'$ stateChangeSuccess'。 手動執行它可以恢復預期的行為。

這是一個已知的問題。 一般工作的解決方法是從'$ stateChangeStart'處理程序中廣播自定義事件,然后從該自定義事件的處理程序中進行狀態轉換。

$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {

    event.preventDefault(); // prevent page from being loaded anyway
    $userRoles.hasPermissions(toState.name).then(function(data) {
        var result = data === "true";
        if (!result) {

            $rootScope.$broadcast('goToPermission');
        }
        else {
            $rootScope.$broadcast('goToState', toState.name);
        }
    });
});

借鑒自: https//github.com/angular-ui/ui-router/issues/178#issuecomment-49156829

我認為弗拉基米爾·古羅維奇的“廣播”解決方案是要走的路,特別是因為他表示這是一個既定的解決方案。

但我想知道一個解決方案,其中緩存權限然后同步查找,也可能是可行的。

autoExecApp.run(['$rootScope', '$state', '$userRoles', function($rootScope, $state, $userRoles) {
    // Create a permissions cache, seeded with 
    // permission to go to the 'permission' state.
    var permissionCache = {
        'permission': true
    };

    // Create a researched list of all possible state names.
    var stateNames = ['stateA', 'stateB', 'stateC'];

    // Now load the cache asynchronously with 
    // `true` for each permission granted.
    stateNames.forEach(function(state) {
        $userRoles.hasPermissions(state).then(function(data) {
            if(data === "true") {
                permissionCache[state] = true;
            }
        });
    });

    // And finally, establish a $stateChangeStart handler 
    // that looks up permissions **synchronously**, 
    // in the permissionCache.
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
        if (!permissionCache[toState.name]) {
            event.preventDefault(); // prevent page from being loaded
            $state.go('permission');
        }
    });
}]);

當然,這個解決方案會有自己的問題:

  • 依賴於對所有可能的州名的良好研究。
  • 在加載緩存之前嘗試的任何狀態更改都將被拒絕。
  • 頁面生命周期中userRoles的任何更改都需要清除和重新加載緩存。

沒有研究/測試,我不能說這些問題是否重要。

為什么不使用解析功能來檢查用戶是否可以訪問您的路線?
像這樣的東西:

autoExecApp.config(['$stateProvider', '$urlRouterProvider', function (
    $stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('index', {
            url: '/index',
            templateUrl: 'partials/index.html'
        })
        .state('permission', {
            url: '/permission',
            templateUrl: 'partials/permissions.html'
        })
    .state('restricted-route', {
      url: '/restricted',
      templateUrl: 'partials/restricted.html',
      resolve: {
        authenticated: function ($q) {
          var deferred = $q.defer();
          $userRoles.hasPermissions(this)
            .then(function (data) {
              var result = data === "true";
              if (result) {
                deferred.resolve();
              } else {
                deferred.reject('unauthorized');
              }
            });
          return deferred.promise;
        }
      }
    });
}]);

$rootScope.$on('$stateChangeError',
  function (event, toState, toParams, fromState, fromParams, rejection) {

    if (rejection.error === 'unauthorized') {
      $state.go('permission');
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM