Rumah >hujung hadapan web >tutorial js >Melaksanakan fungsi pengesahan identiti dan pengesahan borang untuk akses pengguna dalam AngularJS_AngularJS
Authentifizierung
Das gebräuchlichste Berechtigungsdesign ist die rollenbasierte Zugriffskontrolle von RBAC. Die Grundidee besteht darin, dass verschiedene Berechtigungen für Systemvorgänge nicht direkt bestimmten Benutzern gewährt werden, sondern zwischen dem Benutzersatz und dem Berechtigungssatz ein Rollensatz eingerichtet wird. Jede Rolle entspricht einem entsprechenden Satz von Berechtigungen.
Sobald einem Benutzer die entsprechende Rolle zugewiesen wurde, verfügt der Benutzer über alle Bedienberechtigungen dieser Rolle. Dies hat den Vorteil, dass Sie nicht jedes Mal, wenn Sie einen Benutzer erstellen, Berechtigungen zuweisen müssen. Darüber hinaus sind die Berechtigungsänderungen von Rollen viel geringer als die Berechtigungsänderungen von Benutzern. Dies vereinfacht die Benutzerberechtigungsverwaltung und reduziert den Systemaufwand.
In der von Angular erstellten Single-Page-Anwendung müssen wir einige zusätzliche Dinge tun, um eine solche Architektur zu implementieren. Im Hinblick auf das Gesamtprojekt müssen sich Front-End-Ingenieure mit ungefähr drei Stellen befassen
1. UI-Verarbeitung (Bestimmen Sie, ob einige Inhalte auf der Seite basierend auf den Berechtigungen des Benutzers angezeigt werden)
2. Routing-Verarbeitung (wenn der Benutzer auf eine URL zugreift, für die er keine Zugriffsberechtigung hat, springen Sie zu einer Fehlerseite)
3. HTTP-Anforderungsverarbeitung (wenn wir eine Datenanforderung senden und der zurückgegebene Status 401 oder 403 ist, wird diese normalerweise auf eine Fehlerseite umgeleitet)
Implementierung der Zugangsidentitätskontrolle
Zuerst müssen wir alle Berechtigungen des aktuellen Benutzers einholen, bevor Angular gestartet wird. Eine elegantere Möglichkeit besteht darin, diese Zuordnungsbeziehung über einen Dienst zu speichern. Für die UI-Verarbeitung, ob der Inhalt einer Seite entsprechend den Berechtigungen angezeigt wird , sollten wir eine Anweisung verwenden, die implementiert ist. Wenn wir eine Route hinzufügen, müssen wir ihr außerdem ein zusätzliches „Berechtigungs“-Attribut hinzufügen und einen Wert zuweisen, der angibt, welche Rollen berechtigt sind, zu dieser URL zu springen, und dann zuhören Zum RouteChangeStart-Ereignis über Angular. Um zu überprüfen, ob der aktuelle Benutzer Zugriffsrechte auf diese URL hat, ist ein HTTP-Interceptor erforderlich, um zu überwachen, wann der von einer Anfrage zurückgegebene Status 401 oder 403 ist, und um zu einer Fehlerseite zu springen Die Arbeit scheint viel zu sein, ist aber eigentlich ganz einfach zu bewältigen
Geben Sie 401 zurück, führen Sie loginCtrl aus, geben Sie 403 zurück, führen Sie PermissionCtrl aus.
Erhalten Sie die Zuordnungsbeziehung der Berechtigung, bevor Angular ausgeführt wird
Das Angular-Projekt wird über ng-app gestartet, aber in einigen Fällen möchten wir, dass der Start des Angular-Projekts unter unserer Kontrolle steht. In diesem Fall hoffe ich beispielsweise, alle Berechtigungszuordnungsbeziehungen des aktuell angemeldeten Benutzers zu erhalten , und starten Sie dann die Angular-App. Glücklicherweise bietet Angular selbst diese Methode, nämlich angle.bootstrap().
var permissionList; angular.element(document).ready(function() { $.get('/api/UserPermission', function(data) { permissionList = data; angular.bootstrap(document, ['App']); }); });
Mithilfe des obigen Codes können Sie die erhaltene Zuordnungsbeziehung außerdem in einen Dienst einfügen und als globale Variable verwenden.
// app.js var app = angular.module('myApp', []), permissionList; app.run(function(permissions) { permissions.setPermissions(permissionList) }); angular.element(document).ready(function() { $.get('/api/UserPermission', function(data) { permissionList = data; angular.bootstrap(document, ['App']); }); }); // common_service.js angular.module('myApp') .factory('permissions', function ($rootScope) { var permissionList; return { setPermissions: function(permissions) { permissionList = permissions; $rootScope.$broadcast('permissionsChanged') } }; });
(1) Speichern Sie Berechtigungen in der Fabrikvariablen, damit sie im Speicher verbleibt, um die Rolle globaler Variablen zu übernehmen, ohne den Namespace zu verschmutzen.
(2) Übertragen Sie Ereignisse über $broadcast, wenn sich Berechtigungen ändern.
1. So ermitteln Sie anhand der Berechtigungen, ob UI-Komponenten sichtbar oder ausgeblendet sind.
Hier müssen wir selbst eine Anweisung schreiben, die Elemente basierend auf Berechtigungsbeziehungen anzeigt oder ausblendet
<!-- If the user has edit permission the show a link --> <div has-permission='Edit'> <a href="/#/courses/{{ id }}/edit"> {{ name }}</a> </div> <!-- If the user doesn't have edit permission then show text only (Note the "!" before "Edit") --> <div has-permission='!Edit'> {{ name }} </div>
angular.module('myApp').directive('hasPermission', function(permissions) { return { link: function(scope, element, attrs) { if(!_.isString(attrs.hasPermission)) throw "hasPermission value must be a string"; var value = attrs.hasPermission.trim(); var notPermissionFlag = value[0] === '!'; if(notPermissionFlag) { value = value.slice(1).trim(); } function toggleVisibilityBasedOnPermission() { var hasPermission = permissions.hasPermission(value); if(hasPermission && !notPermissionFlag || !hasPermission && notPermissionFlag) element.show(); else element.hide(); } toggleVisibilityBasedOnPermission(); scope.$on('permissionsChanged', toggleVisibilityBasedOnPermission); } }; });Erweitern Sie die vorherige Fabrik:
angular.module('myApp') .factory('permissions', function ($rootScope) { var permissionList; return { setPermissions: function(permissions) { permissionList = permissions; $rootScope.$broadcast('permissionsChanged') }, hasPermission: function (permission) { permission = permission.trim(); return _.some(permissionList, function(item) { if(_.isString(item.Name)) return item.Name.trim() === permission }); } }; });
2. Zugriff basierend auf Berechtigungen auf der Route
Die Idee zur Implementierung dieses Teils ist wie folgt: Wenn wir eine Route definieren, fügen wir ein Berechtigungsattribut hinzu. Der Wert des Attributs ist die Berechtigung für den Zugriff auf die aktuelle URL. Anschließend wird das routeChangeStart-Ereignis verwendet Überwachen Sie die URL-Änderung. Überprüfen Sie bei jeder URL-Änderung, ob die aktuelle URL, die übersprungen werden soll, die Bedingungen erfüllt, und entscheiden Sie dann, ob der Sprung erfolgreich ist oder zur falschen Eingabeaufforderungsseite gesprungen werden soll
app.config(function ($routeProvider) { $routeProvider .when('/', { templateUrl: 'views/viewCourses.html', controller: 'viewCoursesCtrl' }) .when('/unauthorized', { templateUrl: 'views/error.html', controller: 'ErrorCtrl' }) .when('/courses/:id/edit', { templateUrl: 'views/editCourses.html', controller: 'editCourses', permission: 'Edit' }); });
这里依然用到了之前写的hasPermission,这些东西都是高度可复用的.这样就搞定了,在每次view的route跳转前,在父容器的Controller中判断一些它到底有没有跳转的权限即可.
3.HTTP请求处理
这个应该相对来说好处理一点,思想的思路也很简单.因为Angular应用推荐的是RESTful风格的借口,所以对于HTTP协议的使用很清晰.对于请求返回的status code如果是401或者403则表示没有权限,就跳转到对应的错误提示页面即可.
当然我们不可能每个请求都去手动校验转发一次,所以肯定需要一个总的filter.代码如下:
angular.module('myApp') .config(function($httpProvider) { $httpProvider.responseInterceptors.push('securityInterceptor'); }) .provider('securityInterceptor', function() { this.$get = function($location, $q) { return function(promise) { return promise.then(null, function(response) { if(response.status === 403 || response.status === 401) { $location.path('/unauthorized'); } return $q.reject(response); }); }; }; });
写到这里就差不多可以实现在这种前后端分离模式下,前端部分的权限管理和控制了。
表单验证
AngularJS 前端验证指令
var rcSubmitDirective = { 'rcSubmit': function ($parse) { return { restrict: "A", require: [ "rcSubmit", "?form" ], controller: function() { this.attempted = false; var formController = null; this.setAttempted = function() { this.attempted = true; }; this.setFormController = function(controller) { formController = controller; }; this.needsAttention = function(fieldModelController) { if (!formController) return false; if (fieldModelController) { return fieldModelController.$invalid && (fieldModelController.$dirty || this.attempted); } else { return formController && formController.$invalid && (formController.$dirty || this.attempted); } }; }, compile: function() { return { pre: function(scope, formElement, attributes, controllers) { var submitController = controllers[0]; var formController = controllers.length > 1 ? controllers[1] : null; submitController.setFormController(formController); scope.rc = scope.rc || {}; scope.rc[attributes.name] = submitController; }, post: function(scope, formElement, attributes, controllers) { var submitController = controllers[0]; var formController = controllers.length > 1 ? controllers[1] : null; var fn = $parse(attributes.rcSubmit); formElement.bind("submit", function(event) { submitController.setAttempted(); if (!scope.$$phase) scope.$apply(); if (!formController.$valid) return; scope.$apply(function() { fn(scope, { $event: event }); }); }); } }; } }; } };
验证通过
<form name="loginForm" novalidate ng-app="LoginApp" ng-controller="LoginController" rc-submit="login()"> <div class="form-group" ng-class="{'has-error': rc.loginForm.needsAttention(loginForm.username)}"> <input class="form-control" name="username" type="text" placeholder="Username" required ng-model="session.username" /> <span class="help-block" ng-show="rc.form.needsAttention(loginForm.username) && loginForm.username.$error.required">Required</span> </div> <div class="form-group" ng-class="{'has-error': rc.loginForm.needsAttention(loginForm.password)}"> <input class="form-control" name="password" type="password" placeholder="Password" required ng-model="session.password" /> <span class="help-block" ng-show="rc.form.needsAttention(loginForm.password) && loginForm.password.$error.required">Required</span> </div> <div class="form-group"> <button type="submit" class="btn btn-primary pull-right" value="Login" title="Login"> <span>Login</span> </button> </div> </form>
样式如下
前端验证通过会调用login()。