权限控制研究

权限控制是一个成熟的应用系统中不可或缺的一部份,如何设计一个既能满足一般需求,又能不断扩充,并且应用简单完美的权限机制是我所面临的一个问题,现在让我开始吧。
首先,定义一下权限系统的作用,一句话:“我能不能做什么”。
有三个要素,
1.我 定义为 person
2.能不能 定义为 true/false
3.做什么 定义为 function

先定义出一个应用接口
public interface ISecurity{
/*判断一个用户是否具有某项权限*/
public boolean can(int personid, int functionid);
/*给某个用户设置权限*/
public void setSecurity(int personid, int functionid, boolean can);
}

经过具体的实现,可以实现最基本的操作。比如定了三张表
person(id, name) func(id, name) security(person, func)
每一个“我”针对于每一个“做什么”都定义一下“能不能”

接着,问题来了,是否一定要对每一个功能都定义一个能不能?
答:这个问题看你的喜好定了,你可以定只有明确被允许,否则都是不被允许的;也可以定只要没有明确否定,其它都是被允许的。

security.xml
<?xml version="1.0" encoding="GBK" standalone="no" ?>
<!DOCTYPE security SYSTEM "security.dtd">
<security>
<!--
初始化:
1.读入所有操作
2.读入所有角色连同角色的操作
3.读入所有用户连同用户的操作

判断一个用户的权限:
1.取action 的 id
2.取用户所属的角色
3.判断角色是否允许 action,安全起见,禁止的优先级高过允许
4.1 允许,判断用户是否有禁止该 action
4.2 禁止,判断用户是否有允许该 action

注:
1.disable:默认值为 false,这个属性不是必须的,表示操作是否被禁止
例如用户limitguest,本来属于 role 4,有viewuser的权限,但是disable="true"就不能用了
-->
<!--操作-->
<actions>
<action name="all" id="0" display="所有"/>
<action name="signin" id="1" display="登录"/>
<action name="signoff" id="2" display="注销"/>

<action name="modifyselfpass" id="3" display="修改密码"/>
<action name="modifyselfinfo" id="4" display="修改信息"/>

<action name="newuser" id="5" display="新建用户"/>
<action name="deluser" id="6" display="删除用户"/>
<action name="modifyuser" id="7" display="修改用户信息"/>
<action name="viewuser" id="8" display="查看用户信息"/>
</actions>

<!--角色-->
<roles>
<role name="admin" id="1" display="管理员">
<role-action id="0"/>
</role>
<role name="manager" id="2" display="经理">
<role-action id="1 2 3 4"/>
<role-action id="5" disable="true"/>
</role>
<role name="employee" id="3" display="普通员工">
<role-action id="1 2 3 4"/>
</role>
<role name="guest" id="4" display="来宾">
<role-action id="8"/>
</role>
</roles>

<!--用户-->
<users>
<user name="admin" id="1" password="admin" display="管理员" role="1 2"/>
<user name="wuyou" id="2" password="wuyou" display="吴悠" role="2 3"/>
<user name="limin" id="3" password="libo" display="李明" role="3"/>
<user name="guest" id="4" display="来宾" role="4"/>
<user name="limitguest" id="4" display="受限来宾" role="4">
<user-action id="8" disable="true"/>
</user>
</users>
</security>

security.dtd
<?xml version="1.0" encoding="GBK" ?>
<!--声明一个实体-->
<!ENTITY % standardAttribute
"id NMTOKEN #REQUIRED name NMTOKEN #REQUIRED display CDATA #REQUIRED"
>

<!ELEMENT security (actions,roles,users)>

<!ELEMENT actions (action+)>
<!ELEMENT roles (role+)>
<!ELEMENT users (user+)>

<!ELEMENT action EMPTY>
<!ELEMENT role (role-action*)>
<!ELEMENT user (user-action*)>

<!ELEMENT role-action EMPTY>
<!ELEMENT user-action EMPTY>

<!ATTLIST action %standardAttribute;>
<!ATTLIST role %standardAttribute;>
<!ATTLIST user
%standardAttribute;
password NMTOKEN #IMPLIED
role NMTOKENS #REQUIRED
>
<!ATTLIST role-action
id NMTOKENS #REQUIRED
disable (true false) "false"
>
<!ATTLIST user-action
id NMTOKENS #REQUIRED
disable (true false) "false"
>





在第一节中,我提出了一个最原始的需求,并定义了几个接口。

在第二节中,我对这个需求进行了一些细化,设计了一个数据结构和一些基本的操作,可以满足一些低层次的需求。在和 babituo 的讨论中,他给我提出了一些更为详细和现实的需求,我想有必要再进一步进行抽象和设计。Babituo提到“如何针对动态创建的一篇文章进行权限的控制”,及其他一些概念对我很有启发。

目标:简单的核心、简单的定制(程序或是配置)、对于常见的情况会有通用的模板。简单的修改可以应付复杂的需求。学习struts。

首先是三个基本的元素:操作者(主)、操作(谓)、资源(宾)。

操作者指的是发出动作的主体,不一定指具体的人,也可以指一组人,或是指系统中的一个模块,它应该是系统唯一的,具有唯一的ID值。

操作指对资源进行的动作,比如说打开、显示等,同样必须具有唯一的ID值。

资源指被操作的对象,可以指单个对象,比如某个菜单项;也可以指某组对象,比如某组菜单。当然这个某组菜单表现出来的也是单一的一个对象。



操作者权限的继承

操作者的父级的权限是能被下级所继承的,比如“小王”是“研发中心”的员工、那么除非明确说明某些权限是小王禁止使用的,研发中心所有的权限,小王都有。这里的继承不是类的继承,而只是业务方面的一个继承或是包含的关系。

新建资源的权限分配,例如:新建文章的操作权限问题

对于新建的文章一般创建者会具有对这篇文章的所有操作权限,所以我设计两个类:新闻类NewsType和新闻类文章类News。新闻类只有一个实例:newsType,它的子女“新闻A NewsA”是对象是“新闻News”的实例。这里子女NewsA并没有从父亲newsType中继承什么功能。“新闻类”具有一接口init(),表明每生成一个实例,就进行一些初始化操作,这里我们可以定义自动将实例的操作权限赋给创建者。当然,这需要定制程序。

新建的操作者的权限分配

这个和新建资源的权限分配类似,对于某操作者类会有一接口init(),描述新建一个实例时所要进行的操作。

操作的组合

例如对于一篇文章的查看、修改、删除操作统称为对一篇文章的管理操作,具有对一篇文章管理操作的权限同时也具有对这篇文章查看、修改、删除的权限。

没有评论: