一、权限计算相关分析
1.如何存储权限
首先说一下权限保存的问题,一个系统中最多有多少权限呢?一个大的系统中可能有成百上千个权限需要管理。怎么保存这么多的权限?首先,我们使用一个数字中的一位保存一种权限,那么如果现在有3600种权限需要保存,我们就需要一个3600位的数字来保存该权限,首先我们如果不考虑大数的话其它数据类型是没有办法保存这么长的数字的。所以我们为了能够保存这么多的权限,就引入了一个“权限组”的概念,这个权限组只是一个标识权限的容器,我们使用long类型的数字来保存63个权限,假设我们使用long类型的数字来保存权限组,那么很轻松的就能保存住几乎近天文数字个权限。
2.如何保存权限:使用<<运算添加权限
如果有一个添加新权限的界面,该怎么添加权限呢?首先,可以给出权限名称和权限指向的url地址以及权限描述,但是不能提供权限位和权限码的编辑,权限位和权限码的计算需要系统自动计算出来。
保存权限的流程图如下:
3.如何判断用户是否有指定的权限:使用&运算判断权限
我们给给权限一个“public”的属性,我们使用该属性标识该资源是否需要有相关权限才能够访问,如果该属性为true,表示该资源是公共资源,不需要任何权限就能访问。每一个权限都唯一的标志了一个url,所谓的是否有权限实际上就是是否有权限访问该url。
4.如何计算用户的权限总和(rightSum数组)
使用|运算,公式:rightSum[right.pos]=right.pos|rightSum[right.pos];
二、权限实体相关分析
1.为了更加灵活的权限控制,引入角色的概念
角色直接和用户实体挂钩,用户实体不再直接和权限实体关联,而是通过角色实体和权限关联。
一个用户可以有多个角色,一个角色能够属于多个用户;一个角色能够有多个权限,一个权限能够属于多个角色,所以用户和角色之间是多对多的关系,角色和权限之间也是多对多的关系。ER图如下图所示:
2.权限实体分析
在权限管理模块,权限实体是不可再分割的最小实体。
(1)首先权限实体需要有一个权限名rightName,名字只是为了方便理解权限的作用;
(2)url,该url实际上是ActionName,如果带有get类型的参数必须将参数拿掉,比如LoginAction_login.action?username=zhangsan&password=lisi,将其处理之后就变成了LoginAction_login.action
(3)权限码rightCodes,一个表中rightCodes并不是唯一的,它只在对应的权限组中唯一,它使用long类型的数据类型进行保存,形式如1,2,4,8,16,....261
为了避免临界值的麻烦,权限码最大为261
(4)权限位,rightPos,也叫做权限组,这里使用一个整数保存即可,用于标识权限位所在的组,虽然只是起到标识作用,但是实际上却是权限码的容器。
(5)是否是公共资源标识common
(6)权限描述,没什么说的,加上即可。
public class Right implements Serializable{
private static final long serialVersionUID = 7690933329658416384L;
private Integer rightId; //权限唯一标识id
private String rightName="未命名"; //权限名称
private String rightUrl; //将要过滤的URL
private String rightDesc="默认描述"; //权限描述
private Long rightCodes; //权限码
private int rightPos; //权限位,实际上就是权限组的类别
private Boolean common=true; //标识是否为公共资源的标识字段
......
}
权限实体和角色实体之间是多对多的关系,需不需要在权限映射文件中建立关联关系?我们从不会根据权限获取该权限属于哪种角色,所以不要建立权限到角色的关联关系,无用的关联只会给系统带来隐藏的负担。
3.角色实体分析
角色实体需要建立到权限实体的多对多关联关系,但是不应该建立到User实体的关联关系,原因同上。另外增加一个roleValue,使用该值标识是否有超级管理员权限。如果该标识为“-1”,那么将会覆盖其余的所有权限,称为最高权限,可以访问一切资源。
public class Role implements Serializable{
private static final long serialVersionUID = -1585936238538771703L;
private Integer roleId; //Role对象标识id
private String roleName="未命名角色"; //Role对象名称
private String roleValue="0"; //Role对象值,只是在判定是超级管理员的时候有用
private String roleDesc="默认角色描述"; //Role对象描述
//建立Role到Right之间的单向多多对关系
private Set<Right>rights=new HashSet<Right>();//这里必须初始化一下,否则在重用保存/修改页的时候会报错
......
}
4.用户实体
只需要增加一个Set集合并建立到角色实体的多对多关系映射即可。
三、增加权限
流程:导航栏上单击“权限管理”超链接跳转到权限管理界面->在权限管理界面上单击“增加权限”超链接->跳转到增加权限页面上->填写表单成功之后,单击提交,交给RightAction_saveOrUpdateRightPage.action处理,期间调用Service方法保存权限->返回权限管理界面。
当然,最核心的还是Service中的方法:
//添加新权限的过程
public void saveOrUpateRight(Right right){
Integer rightPos;
Long rightCodes;
//首先是针对新创建的情况
if(right.getRightId()==null){
//第一步查找最大权限位和最大权限码
String hql="select max(r.rightPos),max(r.rightCodes) from Right r where r.rightPos=(select max(rr.rightPos) from Right rr)";
Object[] arr=(Object[]) this.rightDao.findUniqueResult(hql);
Integer topRightPos=(Integer) arr[0];
Long topRightCodes=(Long) arr[1];
if(topRightPos==null){
rightPos=0;
rightCodes=1L;
}else{
if(topRightCodes>=(1L<<60)){
rightPos=topRightPos+1;
rightCodes=1L;
}else{
rightPos=topRightPos;
rightCodes=topRightCodes<<1;
}
}
right.setRightPos(rightPos);
right.setRightCodes(rightCodes);
}
this.rightDao.saveOrUpdateEntity(right);
}
四、显示所有权限,略。