因为安全组的同事已经做得相当好,“导致”我可以省掉Web框架的安全设计,也就是腾出了两天的空闲来——真是愉快啊^_^不过,积习难改,还是想尝试着用自己的语言把权限设计这块说明白。以下内容,部分思路来自我的同事,参考了jdon的讨论,并加上自己的一些思考。

需求

从用户角度看,可以描述为
对功能:
1、某人对某项功能可以执行某种操作;
2、某种职位对对某项功能可以执行某种操作;
对数据:
3、某人对某个表可以执行某种动作;
4、某人对某个字段可以执行某种动作;
5、某人对某部分记录可以执行某种动作;
6、某种职位对某个表可以执行某种动作;
7、某种职位对某个字段可以执行某种动作;
8、某种职位对某部分记录可以执行某种动作;

另外,从行政组织上看,人员可以按职位组织起来

总经理
|-总经理助理
|-部门经理1
 |-副经理1
  |--部门员工1
  |--部门员工2
|-部门经理2
  |--部门员工3
  |--部门员工4

接下来,从系统角度看,描述如下:

1、功能必须拆分成为更新的可描述单位,在Web系统中,是page;
2、某人:user
3、某项功能=pages:resource
4、可以执行某种操作:privilege
5、某种职位:user group
6、表、字段、记录:resource
7、行政职位:position

分析设计

首先把资源的问题简单化,只考虑一种情况:以web page作为需要控制的resource。

让我们来考虑,这些东西怎么样才能有机合起来实现我们的控制逻辑。以两两绑定的方式:

1、resouce和privilege是可以绑定的,如:对page1的read权限,对page1的change权限,表示为(r:p){page1:read, page1:change};

2、user和上述(r:p)可以帮定,如George对对page1的read权限,George对page1的change权限,表示为(u:(r:p)){George:(page1:read),George:(page1:change)}

3、user和user groups存在包含关系,即userGroups={user1,user2,user3}

4、web page和module(指功能模块)存在包含关系,即module={page1,page2,page3}

5、position(指上边的行政职位)和user groups存在部分交集,但不等同。

结合1-4,我们已经找到一个比较自然的逻辑(u:(r:p))来表示我们的需求,这其中,user、resource、privilege都是比较清晰的概念,唯独role一直含混不清。事实上有两种:


1、行政职位——这是我们日常生活里在用的:George的role是部门经理,拥有对resouce的privilege,从这个语句上看,部门经理这个role和“对resouce的privilege”(r:p)是等同的吗?第一,总经理和部门员工都可能有这个(r:p);第二,另一部门的部门经理可能没有这个(r:p)。考虑对应的解决。对前者,部门经理自动拥有“部门员工”这个role的所有(r:p),总经理自动拥有“部门经理”这个role的所有(r:p);对后者,区分“部门A的经理”role和“部门B的经理”role。然而,还是有问题员工就不得不也分成“部门A的员工”,“部门B的员工”,那么“部门A的经理”虽然没有“部门A的经理”的(r:p),但拥有“部门B的员工”的(r:p),这时候怎么办?似乎越来越复杂,还是暂时抛开吧。

2、把(r:p)称作“role”,让(r:p)作为role与user/user group关联起来,职位部分的用user group来表示,如“部门A的员工”user group,“经理”user group,同时保留“部门A的经理”user。看起来这样子表示就比较简单明了,且慢,如果有1000项资源,每项资源有5种权限,那么……我们就有了1000*5=5000个role!这倒也罢了,总经理应该有全部的权限,那他就有了——5000个role!真是能者多劳啊!其实真要是全部5000个还好,要是4321个的话,配置人员可真够辛苦的了:得从5000个选项里挑出4321个指定给他,还不能眼花。

以上是我们能够想出的两种途径,我称之为“基于角色设置权限”和“基于权限设置角色”。我认为,授权系统里真正的麻烦就是在这里。暂时无解,只能是两害权衡,择其轻者。

实现

在我们这套系统里,最终选择了“基于权限设置角色”。虽然这种模式让我一想起来就觉得累,但比起“基于角色设置权限”让我一想起来就觉得乱,多少好一些。

授权系统有两种做法,1、编程实现;2、利用J2EE容器管理实现。对于web的内容,我们选择后者。

1、(r:p)=role,那么role-resource的关系存放在web.xml中,如下:
<security-constraint>
    <web-resource-collection>
      <web-resource-name>WebResourceCollection</web-resource-name>
      <description>des</description>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
      <description>test</description>
      <role-name>admin</role-name>
      <role-name>*</role-name>
    </auth-constraint>
</security-constraint>

2、在LDAP realm里存放user/user group-role,由此判断isUserInRole

3、由容器根据上两步的结果是否能够获得授权。

基本上就是这样子,更详细的我就不写了——写这么长的Blog已经很辛苦了^_^必须注意,这样设计之后,对于辅助配置工具的要求是非常高的,否则,根本不满足实用。