Аутентификация AngularJS UI-роутера


376

Я новичок в AngularJS, и меня немного смущает, как я могу использовать angular- "ui-router" в следующем сценарии:

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

Я создал index.htmlдля домашнего раздела его угловое приложение и ui-routerконфигурацию для обработки /loginи /signupпросмотра, и есть еще один файл dashboard.htmlдля раздела приборной панели с его приложением и ui-routerконфигурацией для обработки многих вложенных видов.

Теперь я закончил раздел панели инструментов и не знаю, как объединить эти два раздела с их разными угловыми приложениями. Как я могу сказать домашнему приложению перенаправить приложение на панель инструментов?


1
Можете ли вы поделиться с нами некоторым кодом?
Чанчо

6
@ Чанчо: Я думаю, что дело не в коде, на самом деле, я не знаю, каким кодом мне поделиться.
Ахмед Хашем

да, поделитесь кодом, очень общий вопрос ...
Алиреза,

Ответы:


607

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

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

Во-первых, вам нужен сервис для хранения личности пользователя. Я называю это 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;
      }
    };
  }
])

Во-вторых, вам нужна служба, которая проверяет состояние, в которое пользователь хочет перейти, проверяет, вошли ли они в систему (при необходимости; не требуется для входа, сброса пароля и т. Д.), А затем выполняет проверку роли (если ваше приложение). нужно это). Если они не аутентифицированы, отправьте их на страницу входа. Если они прошли проверку подлинности, но не прошли проверку роли, отправьте их на страницу отказа в доступе. Я называю эту услугу 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. Мы можем вывести пользователя из системы (необходимо подключить его к любому клиентскому или серверному коду, который управляет вашим авторизационным билетом).
  7. Нам не нужно отправлять пользователей обратно на страницу входа каждый раз, когда они перезагружают свой браузер или переходят по ссылке.

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

.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членами роли. Все авторизационные материалы, которые мы обсуждали, будут исходить оттуда.


28
Спасибо, это действительно помогло мне собрать свой собственный код. Кстати, если вы получаете бесконечный цикл маршрутизации (ошибка UI Router), попробуйте $location.pathвместо $state.go.
jvannistelrooy

2
Это отличный ответ, и он мне очень помог. Когда я устанавливаю user = Principal в моем контроллере и пытаюсь вызвать say user.identity (). Name, на мой взгляд, чтобы получить имя пользователя, вошедшего в систему в данный момент, я, кажется, получаю только объект обещания {then: fn, catch: fn, finally :} возвращается, а не фактический объект _identity. Если я использую user.identity.then (fn (user)), я могу получить пользовательский объект, но это похоже на большой код для представления, я что-то упустил?
Марк

4
@ Ir1sh Я бы сначала разрешил идентификацию в контроллере и назначил ее $scope.userв вашей thenфункции. Вы все еще можете ссылаться userв своих взглядах; когда это решено, представление будет обновлено.
moribvndvs

2
@HackedByChinese Я думаю, что ваша демонстрация больше не работает.
Blowie

7
@jvannistelrooy У меня были проблемы с go () to, но после помещения его в то, после вызова noop-функции, подобной этой $q.when(angular.noop).then(function(){$state.go('myState'), все работает как положено. Если я позвоню, $state.goпока другой переход состояния не будет завершен, он не будет работать (я думаю, что по этой причине он не будет работать).
Себастьян

120

Решения, опубликованные до сих пор, на мой взгляд, излишне сложны. Есть более простой способ. Документация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функцию разрешения .

Вы в основном отклоняете обещание, 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()
      }
    }
  }
)

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


6
@FredLackey сказать неаутентифицированный пользователь находится в state A. Они нажимают на ссылку, чтобы перейти, protected state Bно вы хотите перенаправить их logInPage. Если нет $timeout, ui-routerпросто остановит все переходы между состояниями, чтобы пользователь застрял state A. Параметр $timeoutпозволяет ui-routerсначала предотвратить первоначальный переход к, protected state Bпоскольку разрешение было отклонено, а после этого оно перенаправляет на logInPage.
МК Сафи

Где на authenticateсамом деле вызывается функция?
CodyBugstein

authenticateФункция @Imray передается в качестве параметра ui-router. Вы не должны называть это сами. ui-routerназывает это
МК Сафи

Почему вы используете $ locationChangeSuccess вместо $ stateChangeStart?
Draex_

@ PeterDraexDräxler Я в основном следил за документацией. Заметили ли вы разницу при использовании $stateChangeStart?
МК Сафи

42

Самое простое решение - использовать $stateChangeStartи event.preventDefault()отменить изменение состояния, когда пользователь не прошел проверку подлинности, и перенаправить его в состояние аутентификации, которое является страницей входа.

angular
  .module('myApp', [
    'ui.router',
  ])
    .run(['$rootScope', 'User', '$state',
    function ($rootScope, User, $state) {
      $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (toState.name !== 'auth' && !User.authenticaded()) {
          event.preventDefault();
          $state.go('auth');
        }
      });
    }]
  );

6
Я не думаю, что это будет работать, если User.authenticaded () является асинхронным вызовом. Это Святой Грааль, за которым следуют все. Например, если каждое состояние, кроме «логин», защищено, я хочу подтвердить, что пользователь все еще аутентифицирован ПЕРЕД загрузкой любого состояния. Использование resolves - это отстой, потому что они разрешаются только один раз, и чтобы предотвратить загрузку дочерних состояний, вы должны вставить разрешение в EVERY CHILD .
Джейсон

authenticated не является асинхронным вызовом в моем случае: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } вернуть ложь; }; `
Себест

Согласно: stackoverflow.com/a/38374313/849829 , «запуск» идет намного выше «обслуживания» и, следовательно, проблем. Проверка локального хранилища для аутентифицированного статуса, кажется, хороший подход.
Дипак Томас

22

Я думаю, что вам нужно, serviceчтобы обрабатывать процесс аутентификации (и его хранение).

В этом сервисе вам понадобятся несколько основных методов:

  • isAuthenticated()
  • login()
  • logout()
  • так далее ...

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

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

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

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


21

Я создал этот модуль, чтобы помочь сделать этот процесс кусок пирога

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

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

Или также

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

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

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


2
что мешает мне редактировать исходный код во время выполнения и удалять вашего 'admin' || «Бог» и продолжается?
Погриндис

12
Я надеюсь, что любые запросы данных, требующие авторизации, также проверяются на сервере.
Бен Рипли,

24
Это не предназначено для безопасности, авторизация на стороне клиента никогда не бывает, так как вы всегда можете изменить значения. Вы даже можете перехватывать ответы со стороны сервера и оценивать их как «авторизованные». Точка разрешений / авторизации на стороне клиента состоит в том, чтобы не позволять пользователю делать запрещенные вещи для целей UX. Например, если вы выполняете действие только для администратора, даже если пользователь злонамеренно обманывает клиента, чтобы разрешить отправку ограниченного запроса на сервер, сервер все равно возвращает ответ 401. Это, конечно, всегда ответственность за реализацию API @BenRipley действительно
Рафаэль Vidaurre

3
Отличный ответ на вопрос Рафаэля. Всегда защищайте API-интерфейсы, потому что передняя часть - это самая оборотная, спуфинговая вещь из всех, что есть.
Фрэнки Лоскавио

1
Эта проблема с историей уже давно решена @Bohdan. Вы можете безопасно использовать его даже с дополнениями ui-router.
мастерспамбот

16

Я хотел бы поделиться другим решением, работающим с 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

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

Сначала у меня есть и 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 я использую переходы, чтобы проверить состояние autheticated

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

Я построил этот пример, используя некоторый код, найденный в документации $ transitions. Я довольно новый пользовательский интерфейс роутера, но он работает.

Надеюсь, что это может помочь любому.


Это отлично подходит для тех, кто использует более новый маршрутизатор. Спасибо!
MTRO

5

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

if('401' !== toState.name) {
  if (principal.isIdentityResolved()) authorization.authorize();
}

1
Кто-нибудь знает, почему при использовании принятого ответа / настройки, описанных выше, в адресной строке больше не отображается URL-адрес и все фрагменты и параметры строки запроса? После реализации этого адресная строка больше не позволяет создавать закладки для нашего приложения.
Фрэнки Лоскавио,

1
Разве это не должен быть комментарий к одному из существующих ответов? Потому что в OP такого кода нет, и даже не ясно, к какому ответу / к какому коду это относится
TJ

3

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

$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 */ }


3

Используйте $ http Interceptor

Используя перехватчик $ http, вы можете отправлять заголовки в Back-end или наоборот и выполнять свои проверки таким образом.

Отличная статья о перехватчиках $ 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

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

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

Наконец, вам понадобится какой-то способ узнать, может ли ваш вошедший в систему пользователь выполнить определенные операции. Это может быть достигнуто путем добавления функции 'can' к вашей службе аутентификации. Может принимать два параметра: - действие - требуется - (т. Е. «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');
      }
   }
}]

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.