我觉得权限一般解决2个问题。
1)某角色对某个资源是否有操作权限。具体返回true/false,如某人对这张单据是否有察看的权限。
2)某角色可以获得多少个有某操作的权限。返回对象的List,如某人需要获得能读的菜单集合。
而我把权限划分为 操作+资源(资源集)。
用一套xml去划分资源集和操作的关系:
<ResourceSet id="menu" name="菜单">
<Operators>
<Operator id="Read" name="读"/>
<Operator id="Write" name="写"/>
<Operator id="delete" name="删除"/>
</Operators>
</ResourceSet>
在用一个table存放角色与资源的关系(暂且叫权限角色对应表),结构如下
resourceId(varchar)对应是ResourceId
ResourceKey(varchar)资源的Id号,如菜单的Id
RoleAlias(varchar) 角色的名称,我是用别名而不是逻辑Id
PermissionCode (int) 一个2的n-1次方(n是自然数)的和,如上面的第一个是Operator的code为1 第二是2 第三个是4 ,如果与拥有1和3的权限那么这里的数字是5(不知道是否说得清楚,反正就是做位的或运算)
Id(Guid) Primary Key
这样就可以通过配置的方式不断地加入资源。这样就可以解决第一个问题
但是第二个问题的解决比较麻烦,我是用一个叫做资源读取器的概念
<ResourceSet>里面配置多个读取器,使用反射的方式,获得Manager和所带的方法。
如:MenuManager 里面编写一个方法 获得菜单
定义如下(因为我用的是dotNet,可能有点点差别):
IList GetMenus(Guid[] Menus)
而在权限系统里面,我都通过调用ResourceManager的GetResource的方法
获得。
方法定义如下:
IList GetResource(string ResourceSetId,string Operators,string loginid,string ReaderId)
其中,Operators可以输入参数可以为 "Read" 或"Read|Write"
而ReaderId,使ResourceSet里面定义的某个读取器的Id,表明获得资源是需要通过那个读取器完成的。
具体流程是 首先从权限角色对应表中取出可以符合Operations的ResourceKey,然后把ResourceKey转换成为方法的输入参数的类型,通过调用,反射的方法去调用menuManager.GetMenus的方法。
那么第二问题也解决。这个做法由于会调用反射,虽说会有性能问题,但是暂时没有感觉得到,可能,我把资源读取器分为两种,使用Hql(把hbm直接放入权限系统的Hibernate对象中)和反射,前者使用较多,可能这样性能问题不太突出。其中为了灵活还,还可以输入外置变量和输入用户Code等。主要是定义Xml
的时候,多定义了几个标记用于标示。
其中的思路分析的比较透彻..值得借鉴..