Подтвердить что ты не робот

Как получить доступ к свойству "разрешение" корневого состояния UI-Router из $stateChangeStart?

Я пытаюсь внедрить проверку подлинности пользователя и систему проверки доступа в своем приложении, однако я продолжаю бить блокпосты. Я думаю, что на этот раз у меня есть правильный путь, но у меня есть последнее препятствие.

Немного фона: я попытался поместить весь код в $rootScope.on($ startChangeStart), и это сработало, ужасно... но это сработало. Маршрут всегда перенаправлялся, но из-за проверки подлинности на бэкэнд он отображал первую страницу запроса на 1/2 секунды, а затем страницу перенаправления каждый раз. Таким образом, я попытался "приостановить" загрузку страницы, вызвав evt.preventDefault() прямо в начале функции $startChangeStart, которая работала, но попытка вернуть пользователя обратно к исходному маршруту впоследствии вызвала бесконечный цикл в маршрутизаторе.

Итак, после большего количества исследований и чтения много сообщений о стеках я уверен, что "разрешить:" - это правильное место, чтобы поставить проверку подлинности, чтобы гарантировать, что страница не загружается во время ее возникновения, а затем перенаправляет пользователя, если это необходимо из $startChangeStart. ($ state и event всегда undefined в моих попытках внедрить их в функцию разрешения). Кажется, что выигрышная комбинация.

Моя проблема: у меня есть решение в корневом состоянии в моем приложении: "main"

Это было во избежание избыточности кода, однако я не могу определить, как получить доступ к свойствам состояния корня и, следовательно, результат разрешения, из функции $stateChangeStart. ToState - это дочернее состояние, а fromState - либо предыдущее состояние, либо абстрактное состояние с маршрутом "^"...

Должен ли я установить разрешение для каждого дочернего состояния для этого, или есть способ получить доступ к корневому состоянию с этой точки?

Базовая установка приложения:

angular.module('App', ['ui.router', 'ui.bootstrap', 'ui.event', 'AngularGM', 'ngResource'])
.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider){
    $urlRouterProvider
        .when('/home', '/')
        .when('', '/')
        .when('/sign-up/joe', '/sign-up')
        .otherwise('/');

    $stateProvider
        .state('main', {
            url: '',
            abstract: true,
            templateUrl: 'views/main.html',
            controller: 'MainCtrl',
            resolve: {
                checkAccess: ['accountService', function(accountService) {
                    accountService.checkAuth(function(){
                        accountService.checkAccess(function (access){
                            return access;
                        });
                    });
                }]
            }
        })
        .state('main.home', {
            url: '',
            abstract: true,
            templateUrl: 'views/home.html',
            controller: 'HomeCtrl'
        })
        .state('main.home.index', {
            url: '/',
            templateUrl: 'views/home/index.html'
        });


.run(['$rootScope', '$state', '$stateParams', 'accountService', function ($rootScope, $state, $stateParams) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
        console.dir(toState);
        console.dir(toParams);
        console.dir(fromState);
        console.dir(fromParams);
        if (!toState.checkAccess.allowed) {
            event.preventDefault();
            $state.transitionTo(toState.checkAccess.newState);
        }
    });
}]);

Это вывод из вызовов console.dir() двух объектов состояния:

Object
 name: "main.home.index"
 templateUrl: "views/home/index.html"
 url: "/"
 __proto__: Object

Object
 controller: "PlacesCtrl"
 name: "main.places.search"
 templateUrl: "views/places.html"
 url: "/places"
 __proto__: Object

Обновление

Ой, забыл упомянуть, что версия AngularJS - v1.2.0-rc.2

$state.current console.dir()

Object
 abstract: true
 name: ""
 url: "^"
 views: null
 __proto__: Object
4b9b3361

Ответ 1

Да, я считаю, что вы можете получить доступ к корневому состоянию из функции $stateChangeStart.

При использовании чистого AngularJS я обычно использую current.$$route

Например, используя следующий маршрут

.when('/home', {
  title:'Home',
  bodyClass: 'meetings',
  controler: 'HomeCtrl'
})

Я могу получить доступ к состоянию root таким образом

  $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {

   if (current.$$route) {

     $rootScope.title      = current.$$route.title;

     $rootScope.bodyClass  = current.$$route.bodyClass;
   }

 });

Используя ui-router, он немного отличается, так как он называется $state.current. И вы можете получить доступ ко всем свойствам, связанным с любым удаленным вами маршрутом (например: $state.current.url)

Итак, на вашем коде вы могли бы что-то вроде этого

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

      $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
          console.log($state.current.url);
      });
  }]);

Ответ 2

Вам не нужно использовать resolve. Взгляните на мое решение:

app.run ($rootScope, $state, Auth, ngDialog) ->
  $rootScope.$on '$stateChangeStart', (e, to) ->
    if to.authRequired and not Auth.isAuthenticated()
      e.preventDefault()
      Auth.currentUser().then(
        (user) ->
          $state.go(to)
        (failure) ->
          $rootScope.storedState = to
          $state.go('main')
          ngDialog.closeAll()
          ngDialog.open
            template: 'modals/login.html'
            controller: 'loginCtrl'
            className: 'ngdialog-theme-default'
      )

Я использую angular_devise и ngDialog но они являются необязательными, и вы можете реализовать его с помощью собственного пользовательского сервиса.

Ответ 3

Возможно ли сделать перенаправление из вашего accountService? Если вы обнаружите, что пользователь не выполняет функции checkAuth или checkAccess, вы можете предотвратить выполнение обратного вызова и перенаправить пользователя на страницу с ошибкой (или логином).

Что-то еще, что нужно учитывать, это реализация какой-либо переменной/очереди состояний, если вы хотите перенаправить кого-то на страницу входа, чтобы обновить их авторизацию/аутентификацию, а затем вернуться в предыдущее состояние.

Ответ 4

Если вы инициализируете свое состояние стандартным пустым объектом при разрешении, вы сможете управлять им в $stateChangeStart.

$stateProvider
  .state 'home',
    url: "/"
    resolve: {}

...

  $rootScope.$on '$stateChangeStart', (e, toState, toParams, fromState, fromParams) ->
    toState.resolve.x = ->
      $timeout ->
        alert "done"
      , 3000

См. https://github.com/angular-ui/ui-router/issues/1165

Ответ 5

Этот ответ очень поздний, но он может быть полезен.

Разрешения состояния и события $stateChangeStart выполняются одновременно. Когда вы попытаетесь получить доступ к разрешенным данным в $stateChangeStart, он будет недоступен, но он будет доступен, когда произойдет событие $stateChangeSuccess.

Если вы используете $stateChangeStart, вам нужно сделать checkAuth из двух мест $stateChangeStart события и основного разрешения. Поскольку они выполняют параллельное выполнение, по меньшей мере 2 сетевых запроса будут отправляться на сервер для тех же данных.

Вместо этого используйте $stateChangeSuccess. Используя это, вы убедитесь, что ваши разрешения решены, и вы можете проверить доступ. Кроме того, вместо доступа к разрешенным свойствам доступ к разрешенным данным с помощью службы angular.