AngularJS ui-routerログイン認証


376

私はAngularJSを初めて使用しますが、次のシナリオでangular- "ui-router"を使用する方法について少し混乱しています。

2つのセクションで構成されるWebアプリケーションを構築しています。最初のセクションはログインビューとサインアップビューのあるホームページで、2番目のセクションはダッシュボードです(ログイン成功後)。

私はindex.htmlホームセクションのを作成し、その角度のアプリと構成ui-routerを使用/loginして/signupビューを処理dashboard.htmlし、ダッシュボードセクションの別のファイルを使用して、そのアプリと構成ui-routerを使用して多くのサブビューを処理します。

今、私はダッシュボードセクションを終了しましたが、2つのセクションを異なる角度のアプリと組み合わせる方法がわかりません。ホームアプリにダッシュボードアプリにリダイレクトするように指示するにはどうすればよいですか?


1
いくつかのコードを私たちと共有できますか?
Chancho

6
@Chanchoそれはコードに関するものではないと思いますが、実際にはどのコードを共有するべきかわかりません。
アーメドハシェム

はい、コードを共有してください、非常に一般的な質問...
Alireza

回答:


607

私はより良いデモを作成し、これらのサービスのいくつかを使用可能なモジュールにクリーンアップする過程にありますが、ここに私が思いついたものがあります。これは、いくつかの注意事項を回避するための複雑なプロセスであるため、ここでしばらくお待ちください。これをいくつかに分割する必要があります。

このプランクをご覧ください

まず、ユーザーのIDを保存するサービスが必要です。これを呼ぶ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');
              }
            }
          });
      }
    };
  }
])

今、すべてのあなたは、ISが上で聞く行う必要がある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();
      });
    }
  ]);

ユーザーのIDの追跡に関する注意が必要な部分は、既に認証されている場合(たとえば、前のセッションの後にページにアクセスし、認証トークンをCookieに保存している場合、またはページをハードリフレッシュした場合)です。リンクからURLにドロップします)。ui-router動作する方法のため、認証チェックの前に、ID解決を1回実行する必要があります。resolve状態設定のオプションを使用してこれを行うことができます。私は、すべての州が継承するサイトの親州を1つ持っています。

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

ここに別の問題があります... resolve一度だけ呼び出されます。IDルックアップのプロミスが完了すると、解決デリゲートは再度実行されません。したがって、私たちは2つの場所で認証チェックを行う必要があります。1つはでのIDプロミスの解決に従ってresolve、アプリが初めてロード$stateChangeStartされたときをカバーし、もう1つは解決が行われた場合は状態をナビゲートするときをカバーします。

では、これまでに何をしましたか?

  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 2014

2
これは素晴らしい答えであり、多くの助けになりました。私のコントローラーでuser = principalを設定し、ビューでsay user.identity()。nameを呼び出して、現在ログインしているユーザーの名前を取得しようとすると、promiseオブジェクト{then:fn、catch:fn、 :}が返され、実際の_identityオブジェクトは返されません。user.identity.then(fn(user))を使用すると、ユーザーオブジェクトを取得できますが、ビューのコードがたくさんあるようですが、何か不足していますか?
マーク

4
@ Ir1s​​h最初にコントローラーでIDを解決し、それを関数に割り当て$scope.userますthenuserビューでも参照できます。解決されると、ビューが更新されます。
moribvndvs 2014年

2
@HackedByChineseデモが機能していないと思います。
Blowsie 14

7
@jvannistelrooy go()toで問題が発生しましたが、その中に配置した後、このようなnoop関数を呼び出した後$q.when(angular.noop).then(function(){$state.go('myState')、すべてが期待どおりに機能します。$state.go別の状態遷移が完了していないときに呼び出すと、機能しません(それが機能しない理由だと思います)。
セバスチャン

120

私の意見では、これまでに投稿されたソリューションは不必要に複雑です。もっと簡単な方法があります。言うのドキュメントui-routerは聞いて$locationChangeSuccess使用します$urlRouter.sync()、状態の遷移を確認、停止、または再開ためにしています。しかし、それでも実際には機能しません。

ただし、ここでは2つの簡単な代替方法を示します。一つを選ぶ:

解決策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、ユーザーが認証されていない場合は、Promiseを拒否し、ログインページにリダイレクトします。

方法は次のとおりです。

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。がない場合は$timeoutui-router単にすべての状態遷移が停止するため、ユーザーはにとどまりstate Aます。$timeoutことができますui-router最初に初期の移行を防ぐためにprotected state B決意が拒否された、その後に行われますので、それはにリダイレクトlogInPage
MK Safi 2015

authenticate関数は実際にどこで呼び出されますか?
CodyBugstein

@Imray authenticate関数はパラメーターとしてに渡されますui-router。自分で呼び出す必要はありません。ui-routerそれを呼び出します。
MK Safi 2015年

「$ stateChangeStart」の代わりに「$ locationChangeSuccess」を使用しているのはなぜですか?
Draex_ 2015

@PeterDraexDräxler私はほとんどドキュメントに従っていました。を使用して違いに気づきました$stateChangeStartか?
MK Safi 2015

42

最も簡単な解決策は、ユーザーが認証されていないときに状態の変更を使用$stateChangeStartevent.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 sucksは1度しか解決されないので使用します。子の状態が読み込まれないようにするには、解決をEVERY CHILDに挿入する必要があります。
Jason、

私の場合、authenticatedは非同期呼び出しではありません: `this.authenticaded = function(){if(this.currentAccountID!== null){return true; } falseを返します。}; `
sebest 2015年

stackoverflow.com/a/38374313/849829のとおり、「実行」は「サービス」よりも優先されるため、問題が発生します。認証されたステータスについてlocalstorageをチェックすることは、良いアプローチのようです。
Deepak Thomas 2017

22

service認証プロセス(およびそのストレージ)を処理するが必要だと思います。

このサービスでは、いくつかの基本的なメソッドが必要です。

  • isAuthenticated()
  • login()
  • logout()
  • など...

このサービスは、各モジュールのコントローラーに挿入する必要があります。

  • ダッシュボードセクションで、このサービスを使用してユーザーが認証されているかどうかを確認します(service.isAuthenticated()メソッド)。そうでない場合は、/ loginにリダイレクトします。
  • ログインセクションで、フォームデータを使用してservice.login()メソッドでユーザーを認証します

この動作の優れた堅牢な例は、プロジェクトangular-appであり、具体的には、すばらしいアプリケーションに基づいたセキュリティモジュールです HTTP Auth Interceptor Moduleに

お役に立てれば


21

このプロセスを簡単にするためにこのモジュールを作成しました

次のようなことができます。

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

またはまた

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

新品ですが、チェックする価値があります。

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


2
実行時にソースを編集して「管理者」を削除しないようにする方法 「神」と継続?
ポグリンディス2014

12
承認を必要とするデータ要求もサーバーで検証されていることを願っています。
ベン・リプリー

24
これはセキュリティを目的としたものではなく、常に値を変更できるため、クライアント側の承認は決してありません。サーバー側からの応答をインターセプトし、それらを「承認済み」として評価することもできます。クライアント側の権限/承認のポイントは、ユーザーがuxの目的で禁止事項を実行できないようにすることです。たとえば、管理のみのアクションを処理している場合、ユーザーが悪意を持ってクライアントをだまして、サーバーへの制限された要求の送信を許可しても、サーバーは依然として401応答を返します。もちろん、これは常に実装されているAPIの責任です@BenRipley確かに
Rafael Vidaurre

3
質問ラファエルへの素晴らしい回答。フロントエンドはほとんどリバースエンジニアリングが可能で、なりすましが可能なものであるため、常にAPIを保護します。
Frankie Loscavio 2014年

1
歴史に関するこの問題はかなり長い間解決されており、現在は@Bohdanです。ui-routerを追加しても安全に使用できます。
masterspambot

16

UIルーター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 2017

5

これは、無限ルーティングループから抜け出し、$state.go代わりに使用する方法です$location.path

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

1
上記の受け入れられた回答/設定を使用しているときに、アドレスバーにURLとすべてのフラグメントおよびクエリ文字列パラメーターが表示されなくなった理由を誰かが知っていますか?これを実装することで、アドレスバーはアプリをブックマークすることができなくなります。
Frankie Loscavio 2014年

1
これは既存の回答の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

だから私はこの2つのルートにすぐにアクセスでき、オンラインなら他のすべてのルートがチェックされます。

ログインモジュールのルーティングファイル全体は次のとおりです

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」機能を追加することで実現できます。2つのパラメーターを取ることができます。-アクション-必須-(「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.