AngularJS UI 라우터 로그인 인증


376

나는 AngularJS를 처음 사용하고 다음 시나리오에서 angular- "ui-router"를 사용하는 방법에 대해 약간 혼란스러워합니다.

두 섹션으로 구성된 웹 응용 프로그램을 작성 중입니다. 첫 번째 섹션은 로그인 및 가입보기가있는 홈페이지이고 두 번째 섹션은 로그인에 성공한 대시 보드입니다.

index.html각도 앱과 ui-router구성을 사용하여 처리 /login하고 /signup볼 수 있는 홈 섹션을 만들었 dashboard.html으며 앱과 ui-router구성을 사용하여 많은 하위보기를 처리 하는 대시 보드 섹션에 대한 다른 파일 이 있습니다.

이제 대시 보드 섹션을 마쳤으며 두 섹션을 서로 다른 각도 앱과 결합하는 방법을 모르겠습니다. 홈 앱에 대시 보드 앱으로 리디렉션하도록 지시하려면 어떻게해야합니까?


1
우리와 코드를 공유 할 수 있습니까?
Chancho

6
@Chancho 코드가 아니라고 생각합니다. 실제로 어떤 코드를 공유해야하는지 모르겠습니다.
Ahmed Hashem

예, 코드, 매우 일반적인 질문을 공유하십시오 ...
Alireza

답변:


607

더 나은 데모를 만들고 이러한 서비스 중 일부를 사용 가능한 모듈로 정리하는 과정에 있습니다. 그러나 여기에 제가 제시 한 내용이 있습니다. 이는 일부주의 사항을 해결하기위한 복잡한 프로세스이므로 여기에 연결하십시오. 이것을 여러 조각으로 나누어야합니다.

이 펑크를 살펴보십시오 .

먼저, 사용자의 신원을 저장하는 서비스가 필요합니다. 나는 이것을 부른다 principal. 사용자가 로그인했는지 확인할 수 있으며 요청시 사용자 ID에 대한 필수 정보를 나타내는 개체를 확인할 수 있습니다. 필요한 것은 무엇이든 가능하지만 필수는 표시 이름, 사용자 이름, 전자 메일 및 사용자가 속한 역할 (앱에 적용되는 경우)입니다. 교장은 역할 점검을 수행하는 방법도 있습니다.

.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();
      });
    }
  ]);

사용자의 신원을 추적하는 데있어 까다로운 부분은 이미 인증을받은 경우 (예 : 이전 세션 후 페이지를 방문하고 쿠키에 인증 토큰을 저장했거나 페이지를 강제로 새로 고침 한 경우) 확인하는 것입니다. 링크에서 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. 우리는 하지 않습니다 로그인 페이지로 다시 그들의 브라우저를 다시로드하거나 링크를 드롭 할 때마다 사용자를 보내야합니다.

여기서 어디로 가나 요? 글쎄, 당신은 로그인이 필요 지역으로 상태를 구성 할 수 있습니다. 당신은 추가 인증 / 권한이 부여 된 사용자를 요구할 수 dataroles(상속을 사용하려는 경우, 또는 이들의 부모)이 상태로. 여기서는 리소스를 관리자로 제한합니다.

.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 = principal을 설정하고 현재 로그인 한 사용자 이름을 얻기 위해 내보기에서 say user.identity (). name을 호출하려고하면 promise 객체 {then : fn, catch : fn, :}이 반환되었지만 실제 _identity 객체는 아닙니다. user.identity.then (fn (user))을 사용하면 사용자 객체를 얻을 수 있지만 뷰에 대한 많은 코드처럼 보입니다.
Mark

4
@ Ir1sh 컨트롤러에서 먼저 ID를 확인하고 함수 $scope.user에 할당합니다 then. 여전히 user뷰에서 참조 할 수 있습니다. 해결되면보기가 업데이트됩니다.
moribvndvs 2016 년

2
@HackedByChinese 데모가 더 이상 작동하지 않는 것 같습니다.
Blowsie

7
@jvannistelrooy 나는 go ()에 문제가 있었지만 다음과 같은 noop 함수를 호출 한 후 그 안에 넣은 후에 $q.when(angular.noop).then(function(){$state.go('myState')모든 것이 예상대로 작동합니다. $state.go다른 상태 전이가 완료되지 않은 상태에서 전화하면 작동하지 않습니다 (이것이 작동하지 않는 이유라고 생각합니다).
Sebastian

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-routerresolve feature 를 사용 합니다 .

기본적으로 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.
MK Safi

authenticate함수는 실제로 어디에서 호출됩니까?
CodyBugstein 2016 년

@Imray authenticate함수는에 매개 변수로 전달됩니다 ui-router. 직접 호출 할 필요는 없습니다. ui-router그것을 호출합니다.
MK Safi

'$ stateChangeStart'대신 '$ locationChangeSuccess'를 사용하는 이유는 무엇입니까?
Draex_

@ PeterDraexDräxler 나는 대부분 문서를 따르고 있었다. ?를 사용하여 차이점을 발견 했습니까 $stateChangeStart?
MK Safi

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 ()가 비동기 호출이면 이것이 작동하지 않는다고 생각합니다. 그것이 모두의 성배입니다. 예를 들어, "로그인"을 제외한 모든 상태 가 보호되면 상태를로드하기 전에 사용자가 여전히 인증되었는지 확인하고 싶습니다 . 리졸 브를 사용하면 한 번만 해결되므로 자식 상태가로드되지 않도록하려면 리졸 EVERY CHILD에 주입해야합니다 .
Jason

내 경우에는 authenticationd가 비동기 호출이 아닙니다.`this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } 거짓을 반환; }; `
sebest

당 : stackoverflow.com/a/38374313/849829 , '실행'방식으로 서비스의 따라서 문제 '위 온다. 인증 된 상태에 대한 로컬 저장소를 확인하는 것이 좋습니다.
Deepak Thomas

22

service인증 프로세스 (및 저장소)를 처리 하는 것이 필요하다고 생각합니다 .

이 서비스에는 몇 가지 기본 방법이 필요합니다.

  • isAuthenticated()
  • login()
  • logout()
  • 등 ...

이 서비스는 각 모듈의 컨트롤러에 삽입해야합니다.

  • 대시 보드 섹션에서이 서비스를 사용하여 사용자가 인증되었는지 확인하십시오 ( service.isAuthenticated()메소드). 그렇지 않은 경우 / login으로 리디렉션
  • 로그인 섹션에서 양식 데이터를 사용하여 service.login()메소드를 통해 사용자를 인증하십시오.

이 동작에 대한 강력하고 강력한 예는 프로젝트 angular-app 및 특히 멋진 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
런타임에 소스 편집을 중지하고 'admin'을 제거하는 것 || '신'과 계속?
Pogrindis

12
인증이 필요한 모든 데이터 요청도 서버에서 확인되기를 바랍니다.
벤 리플리

24
이것은 보안을위한 것이 아니며, 클라이언트 측 권한 부여는 항상 값을 변경할 수있는 것과는 다릅니다. 서버 측의 응답을 가로 채서 "승인 된"것으로 평가할 수도 있습니다. 클라이언트 측의 권한 / 권한 지점은 사용자가 ux 목적으로 물건을 금지하지 않도록하는 것입니다. 예를 들어 관리자 전용 작업을 처리하는 경우 사용자가 서버에 제한된 요청을 보내도록 클라이언트를 악의적으로 속이더라도 서버는 여전히 401 응답을 반환합니다. 이것은 참으로 물론 항상 API의 책임이 구현되고 @BenRipley입니다
라파엘 Vidaurre

3
질문 라파엘에 대한 큰 반응. 프론트 엔드는 리버스 엔지니어링이 가능하고 스푸핑이 가능한 것이기 때문에 항상 api를 보호하십시오.
Frankie Loscavio

1
역사와 함께이 문제는 지금 @Bohdan 꽤 오랫동안 해결되었습니다. ui-router 엑스트라로도 안전하게 사용할 수 있습니다.
masterspambot

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 에서 전환을 사용하여 인증 된 상태를 확인합니다.

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

$ transitions 문서에서 찾은 일부 코드를 사용하여이 예제를 빌드합니다. 나는 ui 라우터를 처음 접했지만 작동합니다.

그것이 누군가를 도울 수 있기를 바랍니다.


이것은 최신 라우터를 사용하는 사람들에게 좋습니다. 감사!
mtro

5

다음은 우리가 무한 라우팅 루프에서 빠져 나와 $state.go대신에 어떻게 사용되는지 입니다.$location.path

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

1
주소 표시 줄 위에 설명 된 허용 된 답변 / 설정을 사용할 때 더 이상 URL과 모든 조각 및 쿼리 문자열 매개 변수가 표시되지 않는 이유를 아는 사람이 있습니까? 이를 구현하기 때문에 주소 표시 줄에 더 이상 앱을 북마크에 추가 할 수 없습니다.
Frankie Loscavio

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 인터셉터 사용

$ 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

먼저 앱 인증 상태에 대한 아이디어가있는 컨트롤러에 주입 할 수있는 서비스가 필요합니다. 로컬 저장소로 인증 세부 정보를 유지하는 것은 적절한 접근 방법입니다.

다음으로 상태가 변경되기 직전에 인증 상태를 확인해야합니다. 앱에는 인증이 필요한 일부 페이지와 그렇지 않은 페이지가 있으므로 인증을 확인하는 상위 경로를 생성하고 동일한 다른 모든 페이지를 해당 상위의 하위로 만듭니다.

마지막으로, 현재 로그인 한 사용자가 특정 작업을 수행 할 수 있는지 알 수있는 방법이 필요합니다. 인증 서비스에 'can'기능을 추가하면됩니다. -조치-필수-(예 : 'manage_dashboards'또는 'create_new_dashboard')-오브젝트-선택적-조작중인 오브젝트의 두 매개 변수를 사용할 수 있습니다. 예를 들어 대시 보드 개체가있는 경우 dashboard.ownerId === logsInUser.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');
      }
   }
}]

** 면책 조항 : 위 코드는 의사 코드이며 보증이 없습니다 **

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.