使用AngularJS对路由进行安全性处理的方法
简介
自从出现以后,AngularJS已经被使用很长时间了。它是一个用于开发单页应用(SPA)的javascript框架。它有一些很好的特性,如双向绑定、指令等。这篇文章主要介绍Angular路由安全性策略。它是一个可用Angular开发实现的客户端安全性框架。我已经对它进行了测试。除了保证客户端路由安全性外,你也需要保证服务器端访问的安全性。客户端安全性策略有助于减少对服务器进行额外的访问。然而,如果一些人采用欺骗浏览器的手段访问服务器,那么服务器端安全性策略应当能够拒绝未授权的访问。在这篇文章中,我仅对客户端安全性策略进行讨论。
1 在应用模块层面定义全局变量
为应用定义角色:
varroles={ superUser:0, admin:1, user:2 };
为应用定义未授权访问的路由:
varrouteForUnauthorizedAccess='/SomeAngularRouteForUnauthorizedAccess';
2定义授权服务
appModule.factory('authorizationService',function($resource,$q,$rootScope,$location){ return{ //将权限缓存到Session,以避免后续请求不停的访问服务器 permissionModel:{permission:{},isPermissionLoaded:false}, permissionCheck:function(roleCollection){ //返回一个承诺(promise). vardeferred=$q.defer(); //这里只是在承诺的作用域中保存一个指向上层作用域的指针。 varparentPointer=this; //检查是否已从服务获取到权限对象(已登录用户的角色列表) if(this.permissionModel.isPermissionLoaded){ //检查当前用户是否有权限访问当前路由 this.getPermission(this.permissionModel,roleCollection,deferred); }else{ //如果还没权限对象,我们会去服务端获取。 //'api/permissionService'是本例子中的web服务地址。 $resource('/api/permissionService').get().$promise.then(function(response){ //当服务器返回之后,我们开始填充权限对象 parentPointer.permissionModel.permission=response; //将权限对象处理完成的标记设为true并保存在Session, //Session中的用户,在后续的路由请求中可以重用该权限对象 parentPointer.permissionModel.isPermissionLoaded=true; //检查当前用户是否有必须角色访问该路由 parentPointer.getPermission(parentPointer.permissionModel,roleCollection,deferred); } ); } returndeferred.promise; }, //方法:检查当前用户是否有必须角色访问该路由 //'permissionModel'保存了从服务端返回的当前用户的角色信息 //'roleCollection'保存了可访问当前路由的角色列表 //'deferred'是用来处理承诺的对象 getPermission:function(permissionModel,roleCollection,deferred){ varifPermissionPassed=false; angular.forEach(roleCollection,function(role){ switch(role){ caseroles.superUser: if(permissionModel.permission.isSuperUser){ ifPermissionPassed=true; } break; caseroles.admin: if(permissionModel.permission.isAdministrator){ ifPermissionPassed=true; } break; caseroles.user: if(permissionModel.permission.isUser){ ifPermissionPassed=true; } break; default: ifPermissionPassed=false; } }); if(!ifPermissionPassed){ //如果用户没有必须的权限,我们把用户引导到无权访问页面 $location.path(routeForUnauthorizedAccess); //由于这个处理会有延时,而这期间页面位置可能发生改变, //我们会一直监视$locationChangeSuccess事件 //并且当该事件发生的时,就把掉承诺解决掉。 $rootScope.$on('$locationChangeSuccess',function(next,current){ deferred.resolve(); }); }else{ deferred.resolve(); } } }; });
3加密路由
然后让我们用我们的努力成果来加密路由:
varappModule=angular.module("appModule",['ngRoute','ngResource']) .config(function($routeProvider,$locationProvider){ $routeProvider .when('/superUserSpecificRoute',{ templateUrl:'/templates/superUser.html',//路由的view/template路径 caseInsensitiveMatch:true, controller:'superUserController',//路由的angular控制器 resolve:{ //在这我们将使用我们上面的努力成果,调用授权服务 //resolve是angular中一个非常赞的特性,可以确保 //只有当它下面提到的承诺被处理之后 //才将控制器(在本例中是superUserController)应用到路由。 permission:function(authorizationService,$route){ returnauthorizationService.permissionCheck([roles.superUser]); }, } }) .when('/userSpecificRoute',{ templateUrl:'/templates/user.html', caseInsensitiveMatch:true, controller:'userController', resolve:{ permission:function(authorizationService,$route){ returnauthorizationService.permissionCheck([roles.user]); }, } }) .when('/adminSpecificRoute',{ templateUrl:'/templates/admin.html', caseInsensitiveMatch:true, controller:'adminController', resolve:{ permission:function(authorizationService,$route){ returnauthorizationService.permissionCheck([roles.admin]); }, } }) .when('/adminSuperUserSpecificRoute',{ templateUrl:'/templates/adminSuperUser.html', caseInsensitiveMatch:true, controller:'adminSuperUserController', resolve:{ permission:function(authorizationService,$route){ returnauthorizationService.permissionCheck([roles.admin,roles.superUser]); }, } }); });