使用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]);
},
}
});
});