Как дождаться проверки подлинности перед загрузкой состояния по умолчанию в приложении angularjs с помощью ui-router [duplicate]

ОБНОВЛЕНИЕ: перейти к официальному и рекомендованному способу делать это вместо hacky и неофициальный подход для предотвращения / предотвращения неизвестных проблем. Из моего ответа здесь .

На самом деле в документации есть часть

:

Получение сообщений от нескольких отправителей

FCM позволяет нескольким сторонам отправлять сообщения в одно и то же клиентское приложение. Например, предположим, что клиентское приложение является агрегатором статьи с несколькими вкладчиками, и каждый из них должен иметь возможность отправлять сообщение при публикации новой статьи. Это сообщение может содержать URL-адрес, чтобы клиентское приложение могло загрузить статью. Вместо того, чтобы централизовать всю операцию отправки в одном месте, FCM дает вам возможность разрешать каждому из этих авторов отправлять свои собственные сообщения.

Чтобы сделать это возможным, убедитесь, что каждый отправитель генерирует свой собственный идентификатор отправителя . Информацию о том, как получить идентификатор отправителя FCM, см. В документации клиента для вашей платформы. При запросе регистрации клиентское приложение извлекает токен несколько раз, каждый раз с другим идентификатором отправителя в поле аудитории.

Наконец, поделитесь регистрационным маркером с соответствующими серверами приложений (чтобы завершить работу с клиентом регистрации / серверное рукопожатие), и они смогут отправлять сообщения в клиентское приложение, используя свои собственные ключи аутентификации.

Обратите внимание, что существует ограничение на 100 отправителей.

blockquote>

Я думаю, что запутанная, но важная часть здесь:

При запросе регистрации клиентское приложение извлекает токен несколько раз, каждый раз с другим идентификатором отправителя в поле аудитории.

Другими словами, вам нужно будет вызвать getToken() , передавая идентификатор отправителя, и просто "FCM" (например, getToken("2xxxxx3344", "FCM")) в качестве параметров. Вам нужно будет убедиться, что вы вызываете это для каждого отправителя (проекта), который вам нужен.

Также обратите внимание на getToken() документы:

Это блокирующая функция, поэтому не вызывайте ее в основном потоке.

blockquote>

Некоторые дополнительные преимущества:

  • Он не выполняет автоматическое повторное попытку, если он не работает как и по умолчанию.
  • Он возвращает исключение IOException, когда он терпит неудачу.

365
задан Kriem 27 July 2016 в 12:12
поделиться

11 ответов

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

Взгляните на этот plunk .

Сначала вам нужна служба для хранения пользовательских идентичность. Я называю это principal. Он может быть проверен, чтобы узнать, вошел ли пользователь в систему и по запросу он может разрешить объект, представляющий существенную информацию о личности пользователя. Это может быть все, что вам нужно, но основное - это отображаемое имя, имя пользователя, возможно, электронное письмо и роли, к которым принадлежит пользователь (если это относится к вашему приложению). Принципал также имеет методы проверки ролей.

.factory('principal', ['$q', '$http', '$timeout',
  function($q, $http, $timeout) {
    var _identity = undefined,
      _authenticated = false;

    return {
      isIdentityResolved: function() {
        return angular.isDefined(_identity);
      },
      isAuthenticated: function() {
        return _authenticated;
      },
      isInRole: function(role) {
        if (!_authenticated || !_identity.roles) return false;

        return _identity.roles.indexOf(role) != -1;
      },
      isInAnyRole: function(roles) {
        if (!_authenticated || !_identity.roles) return false;

        for (var i = 0; i < roles.length; i++) {
          if (this.isInRole(roles[i])) return true;
        }

        return false;
      },
      authenticate: function(identity) {
        _identity = identity;
        _authenticated = identity != null;
      },
      identity: function(force) {
        var deferred = $q.defer();

        if (force === true) _identity = undefined;

        // check and see if we have retrieved the 
        // identity data from the server. if we have, 
        // reuse it by immediately resolving
        if (angular.isDefined(_identity)) {
          deferred.resolve(_identity);

          return deferred.promise;
        }

        // otherwise, retrieve the identity data from the
        // server, update the identity object, and then 
        // resolve.
        //           $http.get('/svc/account/identity', 
        //                     { ignoreErrors: true })
        //                .success(function(data) {
        //                    _identity = data;
        //                    _authenticated = true;
        //                    deferred.resolve(_identity);
        //                })
        //                .error(function () {
        //                    _identity = null;
        //                    _authenticated = false;
        //                    deferred.resolve(_identity);
        //                });

        // for the sake of the demo, fake the lookup
        // by using a timeout to create a valid
        // fake identity. in reality,  you'll want 
        // something more like the $http request
        // commented out above. in this example, we fake 
        // looking up to find the user is
        // not logged in
        var self = this;
        $timeout(function() {
          self.authenticate(null);
          deferred.resolve(_identity);
        }, 1000);

        return deferred.promise;
      }
    };
  }
])

Во-вторых, вам нужна служба, которая проверяет состояние, к которому пользователь хочет перейти, удостоверяется, что они вошли в систему (при необходимости, не требуется signin, сброс пароля и т. д.), а затем выполняет проверку роли (если ваше приложение нуждается в этом). Если они не аутентифицированы, отправьте их на страницу входа. Если они аутентифицированы, но не выполняют проверку роли, отправьте их на страницу с запретом доступа. Я вызываю эту службу authorization.

.factory('authorization', ['$rootScope', '$state', 'principal',
  function($rootScope, $state, principal) {
    return {
      authorize: function() {
        return principal.identity()
          .then(function() {
            var isAuthenticated = principal.isAuthenticated();

            if ($rootScope.toState.data.roles
                && $rootScope.toState
                             .data.roles.length > 0 
                && !principal.isInAnyRole(
                   $rootScope.toState.data.roles))
            {
              if (isAuthenticated) {
                  // user is signed in but not
                  // authorized for desired state
                  $state.go('accessdenied');
              } else {
                // user is not authenticated. Stow
                // the state they wanted before you
                // send them to the sign-in state, so
                // you can return them when you're done
                $rootScope.returnToState
                    = $rootScope.toState;
                $rootScope.returnToStateParams
                    = $rootScope.toStateParams;

                // now, send them to the signin state
                // so they can log in
                $state.go('signin');
              }
            }
          });
      }
    };
  }
])

Теперь вам нужно только прослушать ui-router $stateChangeStart . Это дает вам возможность изучить текущее состояние, состояние, в котором они хотят перейти, и вставить свою проверку авторизации. Если он терпит неудачу, вы можете отменить переход по маршруту или перейти на другой маршрут.

.run(['$rootScope', '$state', '$stateParams', 
      'authorization', 'principal',
    function($rootScope, $state, $stateParams, 
             authorization, principal)
{
      $rootScope.$on('$stateChangeStart', 
          function(event, toState, toStateParams)
      {
        // track the state the user wants to go to; 
        // authorization service needs this
        $rootScope.toState = toState;
        $rootScope.toStateParams = toStateParams;
        // if the principal is resolved, do an 
        // authorization check immediately. otherwise,
        // it'll be done when the state it resolved.
        if (principal.isIdentityResolved()) 
            authorization.authorize();
      });
    }
  ]);

Сложная часть отслеживания личности пользователя ищет ее, если вы уже прошли аутентификацию (скажем, вы «Посещение страницы после предыдущего сеанса и сохранение токена авторизации в файле cookie, или, может быть, вы сильно обновили страницу или удалили URL-адрес из ссылки). Из-за того, как ui-router работает, вам нужно сделать свое удостоверение личности раз, прежде чем ваши проверки подлинности. Вы можете сделать это, используя опцию resolve в вашей конфигурации состояния. У меня есть одно родительское состояние для сайта, на которое наследуются все государства, что заставляет принципала быть разрешенным, прежде чем что-либо еще произойдет.

$stateProvider.state('site', {
  'abstract': true,
  resolve: {
    authorize: ['authorization',
      function(authorization) {
        return authorization.authorize();
      }
    ]
  },
  template: '<div ui-view />'
})

Здесь есть еще одна проблема ... resolve вызывается только один раз. После того, как ваше обещание для поиска идентичности завершится, он не будет снова выполнять делегат разрешения. Таким образом, мы должны выполнить ваши проверки подлинности в двух местах: один раз в соответствии с вашим обещанием по идентификации, разрешенным в resolve, который распространяется при первом загрузке приложения, и один раз в $stateChangeStart, если разрешение было выполнено, которое охватывает любое время вы перемещаетесь вокруг состояний.

ОК, так что мы сделали до сих пор?

  1. Мы проверяем, когда приложение загружается, если пользователь вошел в систему.
  2. Мы отслеживаем информацию о зарегистрированном пользователе.
  3. Мы перенаправляем их для входа в состояние для состояний, которые требуют, чтобы пользователь вошел в систему.
  4. Мы перенаправляем их на доступ запрещен, если у них нет авторизации для доступа к нему.
  5. У нас есть механизм для перенаправления пользователей обратно в исходное состояние, которое они запросили, если мы нуждались в их входе.
  6. Мы не можем отправить пользователей обратно на страницу входа в систему каждый раз, когда они перезагружают свой браузер или переходят по ссылке.

Куда мы идем отсюда? Ну, вы можете организовать свои штаты в регионах, требующих входа. Вы можете потребовать аутентифицированных / авторизованных пользователей, добавив data с roles в эти состояния (или родительский элемент, если вы хотите использовать наследование). Здесь мы ограничиваем ресурс Admins:

.state('restricted', {
    parent: 'site',
    url: '/restricted',
    data: {
      roles: ['Admin']
    },
    views: {
      'content@': {
        templateUrl: 'restricted.html'
      }
    }
  })

Теперь вы можете контролировать состояние в зависимости от того, что пользователи могут получить доступ к маршруту. Любые другие проблемы? Может быть, меняется только часть представления на основе того, вошли ли они в систему? Нет проблем. Используйте principal.isAuthenticated() или даже principal.isInRole() с любым из многочисленных способов условного отображения шаблона или элемента.

Сначала вставьте principal в контроллер или что-то еще, и привяжите его к чтобы вы могли легко использовать его в своем представлении:

.scope('HomeCtrl', ['$scope', 'principal', 
    function($scope, principal)
{
  $scope.principal = principal;
});

Показать или скрыть элемент:

<div ng-show="principal.isAuthenticated()">
   I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
  I'm not logged in
</div>

и т. д., и так далее. В любом случае, в вашем примере приложения, у вас будет состояние для домашней страницы, которое позволит пропускать не прошедших проверку пользователей. Они могут иметь ссылки на состояния входа или регистрации или иметь эти формы, встроенные в эту страницу. Независимо от того, что вам подходит.

Страницы на панели инструментов могли наследоваться от состояния, которое требует, чтобы пользователи вошли в систему и, скажем, были членом роли User. Все материалы авторизации, которые мы обсуждали, будут поступать оттуда.

597
ответ дан lanoxx 18 August 2018 в 19:56
поделиться
  • 1
    Спасибо, это действительно помогло мне собрать мой собственный код. На боковой ноте, если вы получаете бесконечный цикл маршрутизации (ошибка маршрутизатора UI), попробуйте $location.path вместо $state.go. – jvannistelrooy 23 April 2014 в 12:11
  • 2
    Это отличный ответ, и это очень помогло мне. Когда я устанавливаю user = main в своем контроллере и пытаюсь вызвать say user.identity (). Name в моем представлении, чтобы получить имя пользователя, которое в настоящее время вошло в систему. Мне кажется, что я получаю объект обещания {then: fn, catch: fn, finally :}, а не фактический объект _identity. Если я использую user.identity.then (fn (user)), я могу получить объект пользователя, но это похоже на много кода для представления, я чего-то не хватает? – Mark 21 June 2014 в 15:19
  • 3
    @ Ir1sh Я бы разрешил идентификатор сначала в контроллере и назначил его $scope.user в вашей функции then. Вы по-прежнему можете ссылаться на user в своих представлениях; когда он будет разрешен, представление будет обновлено. – HackedByChinese 21 June 2014 в 22:46
  • 4
    @HackedByChinese Я думаю, что ваша демонстрация больше не работает. – Blowsie 1 July 2014 в 14:01
  • 5
    @jvannistelrooy У меня были проблемы с go (), но после того, как он был помещен внутрь, после вызова функции noop, такой как $q.when(angular.noop).then(function(){$state.go('myState'), все работает так, как ожидалось. Если я назову $state.go, пока другой переход состояния не завершен, то это не сработает (я думаю, что это причина, по которой он не будет работать). – Sebastian 3 July 2014 в 12:29

Мне кажется, вам нужен service, который обрабатывает процесс аутентификации (и его хранение).

В этой службе вам понадобятся некоторые основные методы:

  • isAuthenticated()
  • login()
  • logout()
  • и т. д. ...

Эта услуга должна быть введена в ваших контроллерах каждого модуля:

  • В разделе вашей панели мониторинга используйте эту службу, чтобы проверить подлинность пользователя (метод service.isAuthenticated()). если нет, перенаправляйте / login
  • . В разделе входа в систему просто используйте данные формы для аутентификации пользователя с помощью вашего метода service.login()

. Хороший и надежный пример для этого поведения является проект angular-app и, в частности, его модуль безопасности , который основан на удивительном HTTP-аут-перехватчике

Надеюсь, это поможет

22
ответ дан Cétia 18 August 2018 в 19:56
поделиться

У меня есть другое решение: это решение отлично работает, когда у вас есть только контент, который вы хотите показать при входе в систему. Определите правило, в котором вы проверяете, если вы вошли в систему, а не путь к белым спискам.

$urlRouterProvider.rule(function ($injector, $location) {
   var UserService = $injector.get('UserService');
   var path = $location.path(), normalized = path.toLowerCase();

   if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
     $location.path('/login/signin');
   }
});

В моем примере я спрашиваю, не входит ли я в систему, а текущий маршрут, который я хочу использовать, не является частью `/ login ', потому что мои маршруты в белом списке следующие

/login/signup // registering new user
/login/signin // login to app

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

Вот мой весь файл маршрутизации для модуля входа в систему

export default (
  $stateProvider,
  $locationProvider,
  $urlRouterProvider
) => {

  $stateProvider.state('login', {
    parent: 'app',
    url: '/login',
    abstract: true,
    template: '<ui-view></ui-view>'
  })

  $stateProvider.state('signin', {
    parent: 'login',
    url: '/signin',
    template: '<login-signin-directive></login-signin-directive>'
  });

  $stateProvider.state('lock', {
    parent: 'login',
    url: '/lock',
    template: '<login-lock-directive></login-lock-directive>'
  });

  $stateProvider.state('signup', {
    parent: 'login',
    url: '/signup',
    template: '<login-signup-directive></login-signup-directive>'
  });

  $urlRouterProvider.rule(function ($injector, $location) {
    var UserService = $injector.get('UserService');
    var path = $location.path();

    if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
         $location.path('/login/signin');
    }
  });

  $urlRouterProvider.otherwise('/error/not-found');
}

() => { /* code */ } является синтаксисом ES6, используйте вместо этого function() { /* code */ }

2
ответ дан Chris Incoqnito 18 August 2018 в 19:56
поделиться

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

Затем вам нужно будет проверить состояние auth перед изменениями состояния. Поскольку у вашего приложения есть несколько страниц, которые должны быть аутентифицированы, а другие - нет, создайте родительский маршрут, который проверяет auth, и сделает все остальные страницы, которые требуют того же самого, быть дочерним элементом этого родителя.

Наконец, вам нужно каким-то образом определить, может ли ваш пользователь в настоящий момент выполнять определенные операции. Этого можно достичь, добавив функцию «can» к вашей службе auth. Может принимать два параметра: - действие - требуется - (например, «manage_dashboards» или «create_new_dashboard») - объект - необязательный - объект, который работает. Например, если у вас есть объект панели мониторинга, вы можете проверить, есть ли dashboard.ownerId === loggedInUser.id. (Конечно, информация, переданная от клиента, никогда не должна быть доверенной, и вы всегда должны ее проверять на сервере, прежде чем записывать ее в свою базу данных).

angular.module('myApp', ['ngStorage']).config([
   '$stateProvider',
function(
   $stateProvider
) {
   $stateProvider
     .state('home', {...}) //not authed
     .state('sign-up', {...}) //not authed
     .state('login', {...}) //not authed
     .state('authed', {...}) //authed, make all authed states children
     .state('authed.dashboard', {...})
}])
.service('context', [
   '$localStorage',
function(
   $localStorage
) {
   var _user = $localStorage.get('user');
   return {
      getUser: function() {
         return _user;
      },
      authed: function() {
         return (_user !== null);
      },
      // server should return some kind of token so the app 
      // can continue to load authenticated content without having to
      // re-authenticate each time
      login: function() {
         return $http.post('/login.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      // this request should expire that token, rendering it useless
      // for requests outside of this session
      logout: function() {
         return $http.post('logout.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      can: function(action, object) {
         if (!this.authed()) {
            return false;
         }

         var user = this.getUser();

         if (user && user.type === 'admin') {
             return true;
         }

         switch(action) {
            case 'manage_dashboards':
               return (user.type === 'manager');
         }

         return false;


      }
   }
}])
.controller('AuthCtrl', [
   'context', 
   '$scope', 
function(
   context, 
   $scope
) {
   $scope.$root.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
      //only require auth if we're moving to another authed page
      if (toState && toState.name.indexOf('authed') > -1) {
         requireAuth();
      }
   });

   function requireAuth() {
      if (!context.authed()) {
         $state.go('login');
      }
   }
}]

** ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: вышеуказанный код является псевдокодом и не содержит гарантий **

2
ответ дан colefner 18 August 2018 в 19:56
поделиться

Решения, опубликованные до сих пор, на мой взгляд, излишне сложны. Есть более простой способ. Документация ui-router говорит, что прослушивает $locationChangeSuccess и использует $urlRouter.sync(), чтобы проверить переход состояния, остановить его или возобновить. Но даже это на самом деле не работает.

Однако, вот две простые альтернативы. Выберите один:

Решение 1: прослушивание на $locationChangeSuccess

Вы можете прослушать $locationChangeSuccess, и вы можете выполнить некоторую логику, даже асинхронную логику. Исходя из этой логики, вы можете позволить функции вернуть неопределенное, что приведет к продолжению перехода состояния как обычно, или вы можете сделать $state.go('logInPage'), если пользователь должен пройти аутентификацию. Вот пример:

angular.module('App', ['ui.router'])

// In the run phase of your Angular application  
.run(function($rootScope, user, $state) {

  // Listen to '$locationChangeSuccess', not '$stateChangeStart'
  $rootScope.$on('$locationChangeSuccess', function() {
    user
      .logIn()
      .catch(function() {
        // log-in promise failed. Redirect to log-in page.
        $state.go('logInPage')
      })
  })
})

Имейте в виду, что это фактически не предотвращает загрузку целевого состояния, но оно перенаправляется на страницу входа в систему, если пользователь несанкционирован.

Решение 2: использование состояния resolve

В этом решении вы используете функцию ui-router разрешить

g1].

В основном вы отклоняете обещание в resolve, если пользователь не аутентифицирован, а затем перенаправляет его на страницу входа.

Вот как это делается:

angular.module('App', ['ui.router'])

.config(
  function($stateProvider) {
    $stateProvider
      .state('logInPage', {
        url: '/logInPage',
        templateUrl: 'sections/logInPage.html',
        controller: 'logInPageCtrl',
      })
      .state('myProtectedContent', {
        url: '/myProtectedContent',
        templateUrl: 'sections/myProtectedContent.html',
        controller: 'myProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })
      .state('alsoProtectedContent', {
        url: '/alsoProtectedContent',
        templateUrl: 'sections/alsoProtectedContent.html',
        controller: 'alsoProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })

    function authenticate($q, user, $state, $timeout) {
      if (user.isAuthenticated()) {
        // Resolve the promise successfully
        return $q.when()
      } else {
        // The next bit of code is asynchronously tricky.

        $timeout(function() {
          // This code runs after the authentication promise has been rejected.
          // Go to the log-in page
          $state.go('logInPage')
        })

        // Reject the authentication promise to prevent the state from loading
        return $q.reject()
      }
    }
  }
)

В отличие от первого решения это решение фактически предотвращает загрузку целевого состояния.

112
ответ дан M.K. Safi 18 August 2018 в 19:56
поделиться
  • 1
    Зачем использовать $ timeout? – Fred Lackey 21 April 2015 в 14:11
  • 2
    @FredLackey говорит, что не аутентифицированный пользователь находится в state A. Они нажимают ссылку, чтобы перейти к protected state B, но вы хотите перенаправить их на logInPage. Если нет $timeout, ui-router просто остановит все переходы состояния, поэтому пользователь застрял бы в state A. $timeout позволяет ui-router сначала предотвратить первоначальный переход на protected state B, потому что решение было отклонено, и после этого оно перенаправляется на logInPage. – M.K. Safi 21 April 2015 в 17:53
  • 3
    Где действительно называется функция authenticate? – CodyBugstein 9 June 2015 в 03:46
  • 4
    Функция @Imray authenticate передается как параметр в ui-router. Вам не нужно называть это самостоятельно. ui-router вызывает его. – M.K. Safi 9 June 2015 в 16:05
  • 5
    Почему вы используете '$ locationChangeSuccess' вместо '$ stateChangeStart'? – Draex_ 8 August 2015 в 07:01

I Создал этот модуль, чтобы помочь сделать этот фрагмент процесса

. Вы можете делать такие вещи, как:

$routeProvider
  .state('secret',
    {
      ...
      permissions: {
        only: ['admin', 'god']
      }
    });

Или также

$routeProvider
  .state('userpanel',
    {
      ...
      permissions: {
        except: ['not-logged-in']
      }
    });

Это новенький, но стоит проверить!

https://github.com/Narzerus/angular-permission

21
ответ дан Rafael Vidaurre 18 August 2018 в 19:56
поделиться
  • 1
    Whats, чтобы остановить меня редактирование источника во время выполнения и удаление вашего 'admin' || «бог» и продолжаешь? – Pogrindis 25 September 2014 в 10:49
  • 2
    Я надеюсь, что любые запросы данных, требующие авторизации, также проверяются на сервере. – Ben Ripley 30 September 2014 в 14:36
  • 3
    Это не предназначено для обеспечения безопасности, авторизация на стороне клиента никогда не будет такой, как вы всегда можете изменить значения. Вы даже можете перехватывать ответы со стороны сервера и оценивать их как «разрешенные». Точка разрешений / полномочий на стороне клиента заключается в том, чтобы не позволить пользователю делать запрещенные вещи для целей ux. Например, если вы обрабатываете действие только для администратора, даже если пользователь злонамеренно обманывает клиента, чтобы разрешить отправку ограниченного запроса на сервер, сервер все равно вернет ответ 401. Это, конечно же, всегда ответственность за внедрение api @BenRipley – Rafael Vidaurre 16 October 2014 в 20:36
  • 4
    Отличный ответ на вопрос Рафаэля. Всегда защищайте api, потому что передняя часть - самая обратная инженерная, подтачиваемая вещь, почти есть. – Frankie Loscavio 22 October 2014 в 14:12
  • 5
    Эта проблема с историей решена довольно давно @Bohdan. Вы можете безопасно использовать его даже с дополнительными функциями ui-router. – masterspambot 16 April 2016 в 14:34

Я хотел поделиться другим решением, работающим с ui router 1.0.0.X

Как вы знаете, stateChangeStart и stateChangeSuccess теперь устарели. https://github.com/angular-ui/ui-router/issues/2655

Вместо этого вы должны использовать $ transitions http: // angular-ui. github.io/ui-router/1.0.0-alpha.1/interfaces/transition.ihookregistry.html

Вот как я это достиг:

Сначала я have и AuthService с некоторыми полезными функциями

angular.module('myApp')

        .factory('AuthService',
                ['$http', '$cookies', '$rootScope',
                    function ($http, $cookies, $rootScope) {
                        var service = {};

                        // Authenticates throug a rest service
                        service.authenticate = function (username, password, callback) {

                            $http.post('api/login', {username: username, password: password})
                                    .success(function (response) {
                                        callback(response);
                                    });
                        };

                        // Creates a cookie and set the Authorization header
                        service.setCredentials = function (response) {
                            $rootScope.globals = response.token;

                            $http.defaults.headers.common['Authorization'] = 'Bearer ' + response.token;
                            $cookies.put('globals', $rootScope.globals);
                        };

                        // Checks if it's authenticated
                        service.isAuthenticated = function() {
                            return !($cookies.get('globals') === undefined);
                        };

                        // Clear credentials when logout
                        service.clearCredentials = function () {
                            $rootScope.globals = undefined;
                            $cookies.remove('globals');
                            $http.defaults.headers.common.Authorization = 'Bearer ';
                        };

                        return service;
                    }]);

Тогда у меня есть эта конфигурация:

angular.module('myApp', [
    'ui.router',
    'ngCookies'
])
        .config(['$stateProvider', '$urlRouterProvider',
            function ($stateProvider, $urlRouterProvider) {
                $urlRouterProvider.otherwise('/resumen');
                $stateProvider
                        .state("dashboard", {
                            url: "/dashboard",
                            templateUrl: "partials/dashboard.html",
                            controller: "dashCtrl",
                            data: {
                                authRequired: true
                            }
                        })
                        .state("login", {
                            url: "/login",
                            templateUrl: "partials/login.html",
                            controller: "loginController"
                        })
            }])

        .run(['$rootScope', '$transitions', '$state', '$cookies', '$http', 'AuthService',
            function ($rootScope, $transitions, $state, $cookies, $http, AuthService) {

                // keep user logged in after page refresh
                $rootScope.globals = $cookies.get('globals') || {};
                $http.defaults.headers.common['Authorization'] = 'Bearer ' + $rootScope.globals;

                $transitions.onStart({
                    to: function (state) {
                        return state.data != null && state.data.authRequired === true;
                    }
                }, function () {
                    if (!AuthService.isAuthenticated()) {
                        return $state.target("login");
                    }
                });
            }]);

Вы можете видеть, что я использую

data: {
   authRequired: true
}

для отметьте состояние доступным только в том случае, если оно аутентифицировано.

, затем на .run я использую переходы для проверки состояния, прошедшего проверку.

$transitions.onStart({
    to: function (state) {
        return state.data != null && state.data.authRequired === true;
    }
}, function () {
    if (!AuthService.isAuthenticated()) {
        return $state.target("login");
    }
});

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

Надеюсь, это может помочь кому угодно.

14
ответ дан Sergio Fernandez 18 August 2018 в 19:56
поделиться
  • 1
    Это отлично подходит для тех, кто использует новый маршрутизатор. Благодаря! – mtro 11 July 2017 в 19:53

Вот как мы вышли из бесконечного цикла маршрутизации и все еще использовали $state.go вместо $location.path

if('401' !== toState.name) {
  if (principal.isIdentityResolved()) authorization.authorize();
}
41
ответ дан T J 18 August 2018 в 19:56
поделиться
  • 1
    Кто-нибудь знает, почему при использовании принятого ответа / настройки, описанных выше, адресная строка больше не отображает URL-адрес и все фрагменты и параметры строки запроса? С момента создания этого адреса адресная строка больше не позволяет добавлять в приложение. – Frankie Loscavio 22 October 2014 в 14:44
  • 2
    Я не думаю, что это будет работать, если User.authenticaded () является асинхронным вызовом. Это святой Грааль, которого все ждут. Например, если каждое состояние кроме "login & quot; , я хочу подтвердить, что пользователь все еще аутентифицирован ПЕРЕД , загружая любое состояние. Использование разрешений отстой, потому что они разрешают только один раз, и чтобы предотвратить загрузку дочерних состояний, вы должны ввести решение в КАЖДЫЙ РЕБЕНОК . – Jason 23 October 2015 в 17:53
  • 3
    аутентифицированный не является асинхронным вызовом в моем случае: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } return false; }; ` – sebest 13 November 2015 в 04:30
  • 4
    Разве это не должно быть комментарий к одному из существующих ответов? Потому что в OP нет такого кода, и даже не ясно, какой ответ / какой код он имеет в виду – T J 29 June 2016 в 06:18
  • 5
    Согласно: stackoverflow.com/a/38374313/849829 , «run» выходит выше «обслуживания» и, следовательно, проблем. Проверка localstorage для аутентифицированного статуса кажется хорошим подходом. – Deepak Thomas 31 January 2017 в 05:45

Использовать $ http Interceptor

С помощью перехватчика $ http вы можете отправлять заголовки в конец или наоборот, а также выполнять свои проверки.

Отличная статья о перехватчиках $ http

Пример:

$httpProvider.interceptors.push(function ($q) {
        return {
            'response': function (response) {

                // TODO Create check for user authentication. With every request send "headers" or do some other check
                return response;
            },
            'responseError': function (reject) {

                // Forbidden
                if(reject.status == 403) {
                    console.log('This page is forbidden.');
                    window.location = '/';
                // Unauthorized
                } else if(reject.status == 401) {
                    console.log("You're not authorized to view this page.");
                    window.location = '/';
                }

                return $q.reject(reject);
            }
        };
    });

Поместите это в свою .config или .run функцию.

2
ответ дан TSlegaitis 18 August 2018 в 19:56
поделиться
41
ответ дан T J 7 September 2018 в 04:06
поделиться
41
ответ дан T J 30 October 2018 в 08:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: