Identitätsauthentifizierung kann häufig im Web angewendet werden. In diesem Artikel werden die Fähigkeiten von AngularJS bei der Anwendung der Identitätsauthentifizierung vorgestellt.
Identitätsauthentifizierung
Die gebräuchlichste Methode zur Identitätsauthentifizierung ist die Anmeldung mit Benutzername (oder E-Mail) und Passwort. Dies bedeutet die Implementierung eines Anmeldeformulars, damit sich Benutzer mit ihren persönlichen Daten anmelden können. Das Formular sieht so aus:
<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>
Da es sich um ein Angular-basiertes Formular handelt, verwenden wir die ngSubmit-Direktive, um die Funktion beim Hochladen des Formulars auszulösen. Beachten Sie, dass wir die persönlichen Informationen an die Funktion zum Hochladen des Formulars übergeben, anstatt das Objekt $scope.credentials direkt zu verwenden. Dies erleichtert den Unit-Test der Funktion und reduziert die Kopplung der Funktion an den aktuellen Controller-Bereich. Dieser Controller sieht so aus:
.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); })
Uns ist aufgefallen, dass es hier an tatsächlicher Logik mangelt. Dieser Controller ist so aufgebaut, dass er die Authentifizierungslogik vom Formular entkoppelt. Es ist eine gute Idee, so viel Logik wie möglich aus unserem Controller zu extrahieren und alles in Dienste zu packen. Der Controller von AngularJS sollte die Objekte nur im $scope verwalten (durch Überwachung oder manuelle Bedienung), anstatt zu viele übermäßig schwere Aufgaben zu übernehmen.
Benachrichtigung über Sitzungsänderungen
Die Identitätsauthentifizierung wirkt sich auf den Status der gesamten Anwendung aus. Aus diesem Grund verwende ich lieber Ereignisse (mit $broadcast), um Benutzersitzungsänderungen zu benachrichtigen. Es ist eine gute Idee, alle möglichen Ereigniscodes in einem Mittelweg zu definieren. Dazu verwende ich gerne Konstanten:
.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' })
Eine gute Eigenschaft von Konstanten ist, dass sie wie Dienste nach Belieben an anderen Stellen eingefügt werden können Auf diese Weise. Dadurch können Konstanten von unserem Unit-Test leicht aufgerufen werden. Mit Konstanten können Sie sie später auch einfach umbenennen, ohne eine Reihe von Dateien ändern zu müssen. Der gleiche Trick funktioniert mit Benutzerrollen:
.constant('USER_ROLES', { all: '*', admin: 'admin', editor: 'editor', guest: 'guest' })
Wenn Sie Redakteuren und Administratoren die gleichen Berechtigungen geben möchten, ändern Sie einfach „Editor“ in „Administrator“. '.
Der AuthService
Logik im Zusammenhang mit der Identitätsauthentifizierung und -autorisierung (Zugriffskontrolle) lässt sich am besten im selben Dienst platzieren:
.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; })
Um mich noch weiter von Bedenken hinsichtlich der Identitätsauthentifizierung zu distanzieren, verwende ich einen anderen Dienst (ein Singleton-Objekt, das den Dienststil verwendet), um die Sitzungsinformationen des Benutzers zu speichern. Die Details der Sitzungsinformationen hängen von der Back-End-Implementierung ab, ich gebe jedoch ein allgemeineres Beispiel:
.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; })
Sobald sich der Benutzer anmeldet, wird er Die Informationen sollten an bestimmten Stellen angezeigt werden (z. B. am Avatar des Benutzers in der oberen rechten Ecke). Um dies zu erreichen, muss das Benutzerobjekt durch das $scope-Objekt referenziert werden, vorzugsweise eines, das global aufgerufen werden kann. Obwohl $rootScope die offensichtliche erste Wahl ist, versuche ich, $rootScope nicht zu häufig zu verwenden (eigentlich verwende ich $rootScope nur für globale Ereignisübertragungen). Am liebsten definiere ich dazu einen Controller am Stammknoten der Anwendung oder an einer anderen Stelle, die zumindest höher als der DOM-Baum liegt. Tags sind eine gute Wahl:
<body ng-controller="ApplicationController"> ... </body>
ApplicationController ist ein Container für die globale Logik der Anwendung und eine Option zum Ausführen der Ausführungsmethode von Angular. Daher befindet es sich im Stammverzeichnis des $scope-Baums und alle anderen Bereiche erben von ihm (mit Ausnahme des Isolationsbereichs). Dies ist ein guter Ort, um das currentUser-Objekt zu definieren:
.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; }; })
Wir weisen das currentUser-Objekt nicht wirklich zu, sondern initialisieren lediglich die Eigenschaften im Bereich damit auf currentUser später zugegriffen werden kann. Leider können wir „currentUser“ im untergeordneten Bereich nicht einfach einen neuen Wert zuweisen, da dadurch eine Schatteneigenschaft erstellt würde. Dies ist das Ergebnis der Übergabe primitiver Typen (Strings, Zahlen, Boolesche Werte, undefiniert und null) nach Wert statt nach Referenz. Um Schatteneigenschaften zu verhindern, müssen wir Setter-Funktionen verwenden. Wenn Sie mehr über Angular-Bereiche und prototypische Vererbung erfahren möchten, lesen Sie Understanding Scopes.
Zugriffskontrolle
Identitätsauthentifizierung, also Zugriffskontrolle, gibt es in AngularJS eigentlich nicht. Da wir eine Client-Anwendung sind, liegt der gesamte Quellcode in den Händen des Benutzers. Es gibt keine Möglichkeit, Benutzer daran zu hindern, den Code zu manipulieren, um eine authentifizierte Schnittstelle zu erhalten. Wir können nur die Steuerelemente anzeigen. Wenn Sie eine echte Authentifizierung benötigen, müssen Sie diese serverseitig durchführen, aber das würde den Rahmen dieses Artikels sprengen.
Anzeige von Elementen einschränken
AngularJS verfügt über Anweisungen zum Steuern des Anzeigens oder Ausblendens von Elementen basierend auf Umfang oder Ausdruck: ngShow, ngHide, ngIf und ngSwitch. Die ersten beiden verbergen das Element mithilfe eines