Аутентифікація входу в систему AngularJS ui-router


376

Я новачок у AngularJS, і мене трохи збентежило те, як я можу використовувати кутовий "ui-роутер" у наступному сценарії:

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

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

Тепер я закінчив розділ інформаційної панелі і не знаю, як поєднати ці два секції з різними кутовими додатками. Як я можу сказати домашньому додатку переадресувати на додаток інформаційної панелі?


1
Ви можете поділитися яким-небудь кодом з нами?
Чанчо

6
@Chancho Я думаю, що справа не в коді, я дійсно не знаю, яким кодом слід ділитися.
Ахмед Хашем

так, будь ласка, поділіться кодом, дуже загальне питання ...
Аліреза

Відповіді:


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), спробуйте $location.pathзамість цього $state.go.
jvannistelrooy

2
Це чудова відповідь, і це мені дуже допомогло. Коли я встановлюю user = main у своєму контролері та намагаюся зателефонувати, скажімо, user.identity (). :} повертається, а не фактичний об'єкт _identity. Якщо я використовую user.identity.then (fn (user)), я можу отримати об’єкт користувача, але це здається великим кодом для перегляду, я щось пропускаю?
Марк

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

2
@HackedByChinese Я думаю, що ваша демонстрація більше не працює.
Blowsie

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 () є викликом асинхронізації. Ось святий граал, за яким всі після. Наприклад, якщо будь-який стан, окрім "входу", захищений, я хочу підтвердити, що користувач все ще перевіряється перед тим, як завантажувати будь-який стан Використання роздільної здатності відсмоктує, оскільки вони вирішуються лише один раз, і для того, щоб запобігти завантаженню дочірніх станів, ви повинні ввести роздільну здатність у КОЖНУ ДІТУ .
Джейсон

аутентифікований не є викликом асинхронізації в моєму випадку: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } повернути помилкове; }; `
себест

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

22

Я думаю, вам потрібне, serviceщо керує процесом аутентифікації (та його зберіганням).

У цій службі вам знадобляться кілька основних методів:

  • isAuthenticated()
  • login()
  • logout()
  • тощо ...

Ця послуга повинна бути введена у ваші контролери кожного модуля:

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

Хорошим і надійним прикладом такої поведінки є проект кутового проекту та конкретно його модуль захисту, який базується на дивовижному модулі перехоплення HTTP Auth

Сподіваюсь, це допомагає


21

Я створив цей модуль, щоб допомогти зробити цей процес шматочком торта

Ви можете робити такі речі, як:

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

Або також

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

Це абсолютно новий, але варто перевірити!

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


2
Що мені зупинити редагування джерела під час виконання та видалення вашого "адміністратора" || "бог" і продовжуючи?
Pogrindis

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

24
Це не призначено для безпеки, авторизована клієнтом авторизація ніколи не є, оскільки ви завжди можете змінювати значення. Ви навіть можете перехоплювати відповіді з боку сервера та оцінювати їх як "дозволені". Точка дозволів / авторизації на стороні клієнта полягає у тому, щоб уникнути заборони користувача робити заборонені речі для цілей ux. Наприклад, якщо ви обробляєте дію лише для адміністратора, навіть якщо користувач зловмисно вводить клієнта, щоб дозволити надсилати обмежений запит на сервер, сервер все одно поверне відповідь 401. Це, звичайно, завжди відповідальність за те, що api впроваджується @BenRipley дійсно
Рафаель

3
Чудова відповідь на запитання Рафаеля. Завжди захищайте api, тому що передній кінець є найбільш реверсивною, підданою підробці.
Френкі Лоскавіо

1
Ця проблема з історією вирішується вже досить давно @Bohdan. Ви можете сміливо використовувати його навіть із додатковими додатками у-роутера.
masterpambot

16

Я хотів поділитися ще одним рішенням, що працює з маршрутизатором ui 1.0.0.X

Як ви можете знати, stateChangeStart і stateChangeSuccess тепер застарілі. https://github.com/angular-ui/ui-router/isissue/2655

Натомість слід використовувати $ переходи 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 я використовую переходи для перевірки стану аутентифікації

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

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

Сподіваюся, що це може допомогти будь-кому.


Це відмінно підходить для тих, хто використовує новіший роутер. Дякую!
mtro

5

Ось як ми вийшли з нескінченного циклу маршрутизації і все ще використовуємось $state.goзамість цього$location.path

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

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

1
Хіба це не має бути коментарем до однієї з існуючих відповідей? Тому що такого коду в ОП немає, і навіть не ясно, на яку відповідь / на який код йдеться
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 Перехоплювач

Використовуючи перехоплювач $ 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

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

Далі вам потрібно буде перевірити стан авторизації перед змінами стану. Оскільки у вашому додатку є кілька сторінок, на які потрібно пройти автентифікацію, а інші - ні, створіть батьківський маршрут, який перевіряє автентичність, і зробіть всі інші сторінки, які вимагають того ж, бути дочірніми для цього батьківського.

Нарешті, вам знадобиться якийсь спосіб сказати, чи може ваш поточний користувач виконати певні операції. Цього можна досягти, додавши функцію "може" до вашої служби аутентифікації. Може приймати два параметри: - дія - необхідна - (тобто 'управляти_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.