最近做的项目是使用Angular做一个单页应用,但因为用户有不同的角色(管理员、编辑、普通财务人员等),所以需要进行不同角色的访问控制。
因为后端访问控制的经验比较丰富,所以这里只记录了前端访问控制的实现。请注意,前端最多只能做到显示控制!并不能保证安全,所以后端是一定要做访问控制的!
基于角色的访问控制需要做到两个层面的访问控制:
但在此之前,我们还有一项重要的事要做。
存储用户信息
首先我们要做的,并不是和访问控制有关的事,首先我们要保存好用户信息。包括用户的基本信息,如用户名、真实姓名;以及用户角色。下面是数据结构:
user = {
username:"",
realname:"",
role:""
}
存储的时候就将整个user存储,但存在哪里呢?考虑到必须在任何页面都可以访问到,第一反应是存储到rootScope中,但我们应该尽量避免使用rootScope;除此之外,我们可以存储在顶级的controller或者是全局的constant中,这两种解决方案都可以,但它们的问题就是一旦页面刷新,就不管用了($rootScope也一样)。考虑到user这个变量的生命周期应该要与session相同,所以,我使用了SessionStorage。
在创建controller时,需要加入$sessionStorage:
app.controller('controller',['$sessionStorage', function($sessionStorage){}]);
在登录成功后,将user存储到SessionStorage中:
$sessionStorage.USER = user;
好了,之后通过$sessionStorage就可以获取到用户信息了。
user = $sessionStorage.USER;
控制页面路由的跳转
下面我们开始实现第一点:控制页面路由的跳转。
要做到第一点比较容易,Angular路由改变时会触发$stateChangeStart事件(我用的是stateProvider,所以监听stateChangeStart,如果是用的route或是location,应该监听它们对应的事件),监听此事件,在里面根据访问的url以及用户角色进行权限判断,比如登录的判断就可以在里面做,访问那个url需要登录就直接跳转到登录界面。
首先先写一个auth服务,用于权限认证:
/** * 基于角色的访问控制 */App.service("auth", ["$http","$sessionStorage", function($http, $sessionStorage){ var roles = []; // 从后端数据库获取的角色表 // 从后端获取的角色权限Url映射表,结构为{"role":["/page1", "/page2"……]} var urlPermissions = {}; // 去后端获取 (function(){ // 此处为测试方便,直接赋值了,下面也仅以示例为目的,尽量简单了 roles = ["admin", "user"] urlPermissions = { // 管理员可以访问所用页面 "admin":["*"], // 普通用户可以访问page路径下的所有界面(登录、注册等页面)以及系统主页 "user":["page.*", "app.index", "app.detail"] } })(); function convertState(state) { return state.replace(".", "///.").replace("*", ".*"); } return { // 是否有访问某url的权限 isAccessUrl:function(url) { var user = $sessionStorage.USER; for(var role in roles) { if(user.role.toLowerCase() == roles[role].toLowerCase()) { console.log(urlPermissions[roles[role]]) for(i in urlPermissions[roles[role]]) { var regx = eval("/"+convertState(urlPermissions[roles[role]][i])+"/"); console.log(regx+ " "+ url) if(regx.test(url)) { return true; } } } } return false; } }}])
新闻热点
疑难解答
图片精选