当前位置: 首页 > 科技观察

在Angular中,访问控制是通过前后端分离的方式实现的——RBAC基于角色的访问控制在基于RBAC

时间:2023-03-14 11:42:53 科技观察

权限的设计中比较常见。基本思想是系统操作的各种权限不直接授予特定用户。相反,在用户集和权限集之间建立了一个角色集。每个角色对应一组相应的权限。一旦为用户分配了合适的角色,该用户就拥有该角色的所有操作权限。这样做的好处是不需要每次创建用户都分配权限,只要给用户分配相应的角色即可,而且角色的权限变化远小于用户,这将简化用户的权限管理,减少系统开销。在Angular构建的单页应用中,我们需要做一些额外的事情来实现这样的架构。从整个项目来看,前端工程师需要处理的地方大概有3个。1.UI处理(根据用户拥有的权限,判断页面上的某些内容是否显示)2.路由处理(当用户访问一个没有权限访问的url时,跳转到一个有错误信息)3.HTTP请求处理(当我们发送数据请求时,如果返回状态为401或401,一般会重定向到错误提示页面)如何实现?首先需要在Angular启动前获取当前用户的所有权限,然后比较优雅的方式是通过一个服务Relationship来存储这个映射。UI根据权限处理页面内容是否显示,我们应该通过指令来实现。处理完这些之后,我们还需要在添加路由的时候给它额外添加一个“permission”属性,给它赋值表示哪些角色有权限跳转到这个url,然后检查当前用户是否有权限访问这个url通过Angular监听routeChangeStart事件。***还需要HTTP拦截器来监听,当请求返回状态为401或403时,跳转到错误提示页面。大体的工作就是这些,看似很多,其实一件一件搞定还是挺容易的。在Angular运行之前获取权限的映射关系。Angular项目通过ng-app启动,但在某些情况下我们希望Angular项目的启动在我们的控制之下。比如在本例中,我希望在启动AngularApp之前获取当前登录用户的所有权限映射。幸运的是Angular本身就提供了这种方式,即angular.bootstrap().varpermissionList;angular.element(document).ready(function(){$.get('/api/UserPermission',function(data){permissionList=data;angular.bootstrap(document,['App']);});});仔细看的人可能会注意到这里使用了$.get(),正确使用的是jQuery而不是Angular的$resourcee或者$http,因为此时Angular还没有启动,无法使用它的功能。进一步使用上面的代码可以把得到的映射关系放到一个服务中作为全局变量使用。//app.jsvarapp=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.jsangular.module('myApp').factory('permissions',function($rootScope){varpermissionList;return{setPermissions:function(permissions){permissionList=permissions;$rootScope.$broadcast('permissionsChanged')}};});获取到当前用户的权限集合后,我们将这个集合归档到对应的服务中,然后又做了两件事:(1)将权限存储在工厂变量中,使其一直在内存中,实现全局变量的作用,但不会污染命名空间。(2)通过$broadcast广播事件,当权限发生变化时,如何根据权限来判断UI组件的显示和隐藏这里需要自己写一个指令,根据权限关系来显示或隐藏元素。<!--Iftheuserhaseditpermissiontheshowalink-->{{name}}</a>

{{name}}
看这里理想情况是传递一个has-permission属性来验证权限的名称。当前用户有则显示,没有则隐藏。angular.module('myApp').directive('hasPermission',function(permissions){return{link:function(scope,element,attrs){if(!_.isString(attrs.hasPermission))throw"hasPermissionvaluemustbeastring";varvalue=attrs.hasPermission.trim();varnotPermissionFlag=value[0]==='!';if(notPermissionFlag){value=value.slice(1).trim();}functiontoggleVisibilityBasedOnPermission(){varhasPermission=权限。hasPermission(value);if(hasPermission&&!notPermissionFlag||!hasPermission&¬PermissionFlag)element.show(.hide();}toggleVisibilityBasedOnPermission();scope.$on('permissionsChanged',toggleVisibilityBasedOnPermission);}};});展开前一个工厂:angular.module('myApp').factory('permissions',function($rootScope){varpermissionList;return{setPermissions:function(permissions){permissionList=permissions;$rootScope.$broadcast('permissionsChanged')},hasPermission:function(permission){permission=permission.trim();return_.some(permissionList,function(item){if(_.isString(item.Name))returnitem.Name.trim()===permission});}};});#p#通过权限访问这部分路由的思路是这样的:我们在定义路由的时候,添加一个permission属性,属性的值就是有什么权限可以访问当前url。然后通过routeChangeStart事件始终监视url更改。每次更改url时,检查当前要重定向的url是否满足条件,然后决定是重定向成功还是跳转到错误提示page.router.js: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'});});mainController.jsorindexController.js(简称父层Controller)app.controller('mainAppCtrl',funfunction($scope,$location,permissions){$scope.$on('$routeChangeStart',function(scope,next,current){varpermission=next.$$route.permission;if(_.isString(permission)&&!permissions.hasPermission(permission))$location.path('/unauthorized');});});之前写的hasPermission这里还是用到了,这些东西复用性很强。这样就完成了,在每个视图的路由跳转之前,在父容器的Controller中判断是否有跳转权限就可以了。HTTP请求处理应该是比较好办的,思路也很简单。因为Angularapplication推荐使用RESTful风格的借口,所以HTTP协议的使用非常清晰。如果请求返回的状态码是401或者403,说明没有权限,直接跳转到相应的错误提示页面即可。当然,我们不可能每个请求都人工验证并转发一次,所以通用过滤器肯定是需要的。代码如下:angular.module('myApp').config(function($httpProvider){$httpProvider.responseInterceptors.push('securityInterceptor');}).provider('securityInterceptor',function(){this.$get=function($location,$q){returnfunction(promise){returnpromise.then(null,function(response){if(response.status===403||response.status===401){$location.path('/unauthorized');}return$q.reject(response);});};};});写到这里差不多就可以实现了,在这种前后端分离的模式下,实现了前端部分的权限管控。请给我留言。原文链接:http://my.oschina.net/blogshi/blog/300595