Autenticación
La forma más común en el diseño de permisos es el control de acceso basado en roles de RBAC. La idea básica es que varios permisos para las operaciones del sistema no se otorgan directamente a usuarios específicos, sino para establecer una recopilación de roles entre el conjunto de usuarios y el conjunto de permisos. Cada rol corresponde a un conjunto correspondiente de permisos.
Una vez que el usuario ha sido asignado el rol apropiado, el usuario tiene todos los permisos operativos para el rol. La ventaja de esto es que no hay necesidad de asignar permisos cada vez que se crea un usuario, solo asigne el papel correspondiente del usuario, y los cambios de permiso del rol son mucho menos que los de los cambios de permiso del usuario, lo que simplificará la administración de permisos del usuario y reducirá la sobrecarga del sistema.
En una aplicación de una sola página creada por Angular, necesitamos hacer algunas cosas adicionales para implementar dicha arquitectura. Desde la perspectiva general del proyecto, hay alrededor de 3 lugares con los que los ingenieros frontales necesitan lidiar.
1. Procesamiento de la interfaz de usuario (juzgar si algún contenido en la página se muestra en función de los permisos propiedad del usuario)
2. Procesamiento de enrutamiento (cuando el usuario accede a una URL de que no tiene permiso para acceder, salta a una página con un mensaje de error)
3. Procesamiento de solicitudes HTTP (cuando enviamos una solicitud de datos, si el estado devuelto es 401 o 403, generalmente se redirige a una página con un mensaje de error)
Implementación del control de identidad de acceso
Primero, debe obtener todos los permisos del usuario actual antes de que Angular comience, y luego la forma más elegante es almacenar esta relación de mapeo a través de un servicio. Para si el contenido en una página se muestra de acuerdo con los permisos por la interfaz de usuario. Después de procesarlos, necesitamos agregar un atributo adicional de "permiso" para agregar una ruta al agregar una ruta, y asignarle un valor para indicar qué roles con permisos pueden saltar a esta URL, y luego escuchar el evento RoutechangeStart a través de Angular para verificar si el usuario actual tiene acceso a esta URL. Finalmente, se necesita un interceptor HTTP para monitorear cuando el estado devuelto por una solicitud es 401 o 403, salte a la página a una página de indicación de error. Lo más o menos esto es lo que es, parece demasiado, pero en realidad es muy fácil de manejar.
Return 401, ejecute loginctrl, return 403, ejecute permissionCtrl.
Obtenga la relación de mapeo de permiso antes de que Angular funcione
El proyecto angular se inicia a través de NG-APP, pero en algunos casos esperamos que el proyecto angular esté bajo nuestro control. Por ejemplo, en este caso, espero obtener todas las relaciones de mapeo de permisos del usuario actualmente registrado y luego comenzar la aplicación Angular. Afortunadamente, Angular mismo proporciona este método, es decir, angular.bootstrap ().
var de la lista de permisos; angular.element (documento) .Ready (function () {$ .get ('/api/userPermission', function (data) {permissionList = data; angular.bootstrap (documento, ['app']);});});Aquellos que leen cuidadosamente pueden notar que el uso de $ .get () se usa aquí, y no hay ningún error usando jQuery en lugar del recurso $ de Angular o $ http, porque en este momento, Angular aún no ha comenzado, y no podemos usar su función.
Utilice aún más el código anterior para colocar la relación de mapeo obtenida en un servicio como una variable global.
// app.js var app = angular.module ('myApp', []), permisoList; app.run (function (permissions) {permissions.setPermissions (permiso list)}); angular.element (documento) .Ready (function () {$ .get ('/api/userPermission', function (data) {permissionList = data; angular.bootstrap (documento, ['app']);});}); // Common_Service.js angular.module ('myApp') .factory ('permissions', function ($ rootscope) {var permisoList; return {setPermissions: function (permissions) {permissionList = permissions; $ rootscope. $ broadcast ('permissionsionschanged')}};});Después de obtener el conjunto de permisos del usuario actual, archivamos este conjunto en el servicio correspondiente y luego hicimos 2 cosas más:
(1) Almacene los permisos en las variables de fábrica para que siempre estén en la memoria, dando cuenta del papel de las variables globales, pero no contaminan el espacio de nombres.
(2) Evento de transmisión a través de $ transmisión, cuando cambian los permisos.
1. Cómo determinar la potencia visible y oculta del componente de la interfaz de usuario basada en permisos
Aquí necesitamos escribir una directiva nosotros mismos, que mostrará u ocultará elementos basados en relaciones de permiso.
< }} </div>
Aquí veo una situación ideal en la que puede aprobar el nombre del permiso de verificación de la propiedad de la permisión, y si el usuario actual lo tiene, se mostrará, y si no hay NO, se ocultará.
Angular.module ('myApp'). Directiva ('HasperMission', function (permissions) {return {link: function (scope, element, attrs) {if (! _. isstring (attrs.haspermission)) lanzar "el valor de haspermission debe ser una cadena"; var valor = attrs.haspermission.trim (); var noperMississionsflag = value [0]; if (NotPermissionFlag) {value = value.slice (1) .trim (); toggleVisabilityBaseDonPermission ();Expandir la fábrica anterior:
angular.module ('myApp') .Factory ('permissions', function ($ rootscope) {var permisoList; return {setPermissions: function (permissions) {permissionList = permissions; $ rootscope. $ broadcast ('permissionsChanged')}, HaSpermission: function (permiso) {permiso de permississss. _.2. Acceso basado en permiso en la ruta
La idea de esta parte de la implementación es la siguiente: cuando definimos una ruta, agregamos un atributo de permiso, y el valor del atributo es qué permisos tenemos para acceder a la URL actual. Luego, seguimos escuchando los cambios de URL a través del evento RoutechangeStart. Cada vez que cambiemos la URL, verifique si la URL a redirigir cumple con las condiciones y luego decidimos si se redirigirá con éxito o a la página de indicación de error.
app.config (function ($ ruteProvider) {$ ruteProvider .When ('/', {TemplateUrl: 'Views/ViewCourses.html', controlador: 'ViewCoursSctrl'}). .When ('/cursos/: id/edit', {TemplateUrl: 'vistas/editCourses.html', controlador: 'editCourses', permiso: 'editar'});MainController.js o indexController.js (en resumen, es el controlador de la capa principal)
app.controller ('mainAppCtrl', function ($ scope, $ ubicación, permisos) {$ scope. $ on ('$ rutechangeStart', function (scope, next, actual) {var permiso = next. $$ ruta.permission; if (_. isstring (permiso) &! permissions.haspermission (permiso)) $ ubicación.path ('/'/'/') });El haspero escrito antes todavía se usa aquí, y estas cosas son muy reutilizables. Esto está hecho. Antes de cada salto de ruta de vista, simplemente juzgue si tiene permiso para saltar en el controlador del contenedor principal.
3. Procesamiento de solicitudes HTTP
Esto debería ser relativamente fácil de manejar, y la idea es muy simple. Debido a que las aplicaciones angulares recomiendan excusas de estilo RESTful, el uso del protocolo HTTP es muy claro. Si el código de estado devuelto por la solicitud es 401 o 403, significa que no hay permiso, por lo que puede saltar a la página de solicitado de error correspondiente.
Por supuesto, no podemos verificar y reenviar manualmente cada solicitud una vez, por lo que definitivamente debemos necesitar un filtro total. El código es el siguiente:
angular.module ('myApp') .config (function ($ httpProvider) {$ httpprovider.esponseinterceptors.push ('seguridadinterceptor');}) .provider ('seguridadinterceptore', function () {this. $ get = function ($ ubicación, $ q) {function de regreso) {regreso promety.then (nelle (neco (respuesta) if (respuesta.status === 403 ||Al escribir esto, casi puede realizar la gestión y el control del permiso de la parte front-end en este modo de separación frontal.
Verificación de forma
Directiva de verificación front-end de AngularJS
var rcSubmitDirective = {'rcsubmit': function ($ parse) {return {restrict: "a", request: ["rcsubmit", "? form"], controler: function () {this.attempted = false; var FormController = null; this.setattempted = function () {this.attempted = true; }; this.setFormController = function (controlador) {formController = controlador; }; this. if (FieldModelController) {return FieldModelController. $ Invalid && (FieldModelController. $ Dirty || this.attempted); } else {return FormController && FormController. $ Invalid && (FormController. $ Dirty || this.attempted); }}; }, compilar: function () {return {pre: function (scope, formeLement, atributes, controladores) {var SubtController = controladores [0]; var formyController = controladores.length> 1? controladores [1]: nulo; SubtController.SetFormController (FormController); scope.rc = scope.rc || {}; scope.rc [attributes.name] = SubtController; }, post: function (alcance, formelemento, atributos, controladores) {var SubtController = controladores [0]; var formyController = controladores.length> 1? controladores [1]: nulo; var fn = $ parse (attributes.rcsubmit); formeLement.bind ("enviar", función (evento) {SubtController.setAtTempted (); if (! Copo. $$ fase) ACPO. $ Aplicar (); if (! FormController. $ Valid) return; Scope. $ Aplication (function () {fn (alcance, {$ evento: event});});}); }}; }}; }}; }}; }}; }}; }}; }}; }};Verificación aprobada
<form de nombre = "loginform" novalidate ng-app = "loginapp" ng-Controller = "logincontroller" rc-subMit = "login ()"> <div ng-class = "{'has-error': rc.Loginform.needSattent (loginform.username)}>"> <input name = "userName" type "type" type "type" type "tyte =" texting "staveAntent (" Tipo de lugar ". ng-model = "session.username"/> <span ng-show = "rc.form.needsattention (loginform.username) && loginform.username. $ error.required"> requerido </span> </div> <divs-class = "{'ha-sorror': rc.loginform.needsattent (loginform.passwortsworts) type = "Password" PlaceHolder = "Password" requerido ng-model = "session.password"/> <span ng-show = "rc.form.needsattention (loginform.password) && loginform.password. $ error.required"> requerido </span> </div> <div> <button type = "enviar" valor = "login"> <span> login </span> </</span button </button </button </div> <button type = "enviar" valor = "login"> <span> login </span> </span button </button </button </button </div>El estilo es el siguiente
Se llamará al inicio de sesión () después de que pase la verificación frontal.