ID 認証
最も一般的な ID 認証方法は、ユーザー名 (または電子メール) とパスワードを使用してログインすることです。これは、ユーザーが個人情報を使用してログインできるようにログイン フォームを実装することを意味します。フォームは次のようになります:
<form name="loginForm" ng-controller="LoginController" ng-submit="login(credentials)" novalidate> <label for="username">Username:</label> <input type="text" id="username" ng-model="credentials.username"> <label for="password">Password:</label> <input type="password" id="password" ng-model="credentials.password"> <button type="submit">Login</button> </form>
これは Angular を利用したフォームであるため、フォームをアップロードするときに ngSubmit ディレクティブを使用して関数をトリガーします。注意すべき点の 1 つは、$scope.credentials オブジェクトを直接使用するのではなく、個人情報をアップロード フォーム関数に渡すことです。これにより、関数の単体テストが容易になり、現在のコントローラー スコープへの関数の結合が軽減されます。コントローラーは次のようになります:
.controller('LoginController', function ($scope, $rootScope, AUTH_EVENTS, AuthService) { $scope.credentials = { username: '', password: '' }; $scope.login = function (credentials) { AuthService.login(credentials).then(function (user) { $rootScope.$broadcast(AUTH_EVENTS.loginSuccess); $scope.setCurrentUser(user); }, function () { $rootScope.$broadcast(AUTH_EVENTS.loginFailed); }); };javascript:void(0); })
ここには実際のロジックが欠如していることに気付きました。このコントローラーは、認証ロジックをフォームから切り離すためにこのように作成されています。コントローラーからできるだけ多くのロジックを抽出し、それをすべてサービスに配置することをお勧めします。 AngularJS のコントローラーは、過度に重いタスクを引き受けるのではなく、(監視または手動操作を使用して) $scope 内のオブジェクトのみを管理する必要があります。
セッション変更の通知
ID認証はアプリケーション全体の状態に影響します。このため、私はイベント ($broadcast を使用) を使用してユーザー セッションの変更を通知することを好みます。考えられるすべてのイベント コードを中間点で定義することをお勧めします。私はこれを行うために定数を使用するのが好きです:
.constant('AUTH_EVENTS', { loginSuccess: 'auth-login-success', loginFailed: 'auth-login-failed', logoutSuccess: 'auth-logout-success', sessionTimeout: 'auth-session-timeout', notAuthenticated: 'auth-not-authenticated', notAuthorized: 'auth-not-authorized' })
定数の良い特徴は、サービスと同じように、自由に他の場所に注入できることです。これにより、単体テストで定数を簡単に呼び出すことができるようになります。定数を使用すると、大量のファイルを変更しなくても、後で簡単に名前を変更できます。同じトリックがユーザーの役割でも機能します:
.constant('USER_ROLES', { all: '*', admin: 'admin', editor: 'editor', guest: 'guest' })
編集者と管理者に同じ権限を与えたい場合は、「editor」を「admin」に変更するだけです。
AuthService
認証と承認 (アクセス制御) に関連するロジックは、同じサービスに配置するのが最適です:
.factory('AuthService', function ($http, Session) { var authService = {}; authService.login = function (credentials) { return $http .post('/login', credentials) .then(function (res) { Session.create(res.data.id, res.data.user.id, res.data.user.role); return res.data.user; }); }; authService.isAuthenticated = function () { return !!Session.userId; }; authService.isAuthorized = function (authorizedRoles) { if (!angular.isArray(authorizedRoles)) { authorizedRoles = [authorizedRoles]; } return (authService.isAuthenticated() && authorizedRoles.indexOf(Session.userRole) !== -1); }; return authService; })
認証の心配からさらに遠ざけるために、私は別のサービス (シングルトン オブジェクト、サービス スタイル) を使用して、ユーザーのセッション情報を保存します。セッション情報の詳細はバックエンドの実装によって異なりますが、より一般的な例を示します:
.service('Session', function () { this.create = function (sessionId, userId, userRole) { this.id = sessionId; this.userId = userId; this.userRole = userRole; }; this.destroy = function () { this.id = null; this.userId = null; this.userRole = null; }; return this; })
ユーザーがログインすると、その情報は特定の場所 (右上隅のユーザーのアバターやそんな感じ) )。これを実現するには、ユーザー オブジェクトが $scope オブジェクトによって参照される必要があり、できればグローバルに呼び出すことができるオブジェクトを参照する必要があります。 $rootScope が最初の選択肢であることは明らかですが、私は $rootScope を使いすぎないよう自制しています (実際には $rootScope はグローバル イベント ブロードキャストにのみ使用しています)。私がこれを行うことを好む方法は、アプリケーションのルート ノード、または少なくとも DOM ツリーより上位のどこかにコントローラーを定義することです。 タグは良い選択です:
<body ng-controller="ApplicationController"> ... </body>
ApplicationController はアプリケーションのグローバル ロジックのコンテナーであり、Angular の run メソッドを実行するためのオプションです。したがって、これは $scope ツリーのルートにあり、他のすべてのスコープはそこから継承します (分離スコープを除く)。ここは currentUser オブジェクトを定義するのに適した場所です:
.controller('ApplicationController', function ($scope, USER_ROLES, AuthService) { $scope.currentUser = null; $scope.userRoles = USER_ROLES; $scope.isAuthorized = AuthService.isAuthorized; $scope.setCurrentUser = function (user) { $scope.currentUser = user; }; })
currentUser オブジェクトを実際に割り当てるのではなく、後で currentUser にアクセスできるようにスコープ付きプロパティを初期化するだけです。残念ながら、シャドウ プロパティが作成されるため、子スコープの currentUser に単純に新しい値を割り当てることはできません。これは、プリミティブ型 (文字列、数値、ブール値、未定義、null) を参照ではなく値で渡した結果です。シャドウプロパティを防ぐには、セッター関数を使用する必要があります。 Angular スコープとプロトタイプの継承について詳しく知りたい場合は、「スコープについて」を参照してください。
アクセス制御
ID認証、つまりアクセス制御は、実はAngularJSには存在しません。私たちはクライアント アプリケーションであるため、すべてのソース コードはユーザーの手にあります。ユーザーがコードを改ざんして認証されたインターフェイスを取得することを防ぐ方法はありません。私たちにできることはコントロールを表示することだけです。真の認証が必要な場合は、サーバー側で認証を行う必要がありますが、それはこの記事の範囲外です。
要素の表示を制限する
AngularJS には、スコープまたは式に基づいて要素の表示または非表示を制御するディレクティブ (ngShow、ngHide、ngIf、ngSwitch) があります。最初の 2 つは