本文涉及权限管理的一种面向对象模型的方法和实现。通过分析每次访问发生场景的各要素,并对各要素进行抽象而形成的一种模型,并可用于实现权限访问控制。原谅我自己取了什么“四维权限管理模型”“访问控制矩阵(ACM)”这样难听的名字,还多少有故弄玄虚之嫌,但我在半年前只有这样的见识。 1、访问控制矩阵(ACM) 说明:任意对系统使用者产生价值的用例中的操作均在以下四个维度加以控制: l Operator(操作者权限控制): 进行某种操作时,操作的主体。分为:用户,角色,单位 l OperateMethod(操作方法权限控制): 操作的功能确定,如:读、写、查、删等 l Object(操作对象权限控制): 操作的影响对象,通常是某种业务对象,如:表单 l Object.Fields(操作对象属性项权限控制) 业务要求对选项敏感的对象属性项,如:表单的某数据项、表单上的简单控件等 2、ACM中四维数据的组成 Operator:操作者,根据业务的需要设定控制项目主要分为用户、角色、单位三种。根据业务的需要,可以控制Operator的作用先后顺序或交并运行规则; Operate Method:操作方法,根据业务操作的对象的不同,可能是业务操作或是底层的CRUD操作; Object:操作对象,当前操作的对象,根据业务需求可以是:业务对象,如:项目、表单; Object Fields:操作对象属性,要求与权限控制绑定的对象的数据项。如:表单字段、表单控件等。 3、原理简述 ACM在权限管理和访问控制时的作用原理。一个ACM是由若干控制系统某项操作行为的若干要素组成的规则矩阵。设想一个场景,当某项操作进行时,必然有如下元素:操作者、操作方法、操作对象。所有ACM就指定了一次操作必须满足的各元素的条件。如:有ACM如下:“李厚强”、“修改”、“用户信息”。就代表:“李厚强可以修改用户信息”。当然这是一个简单的例子,事实上,情况远比这个例子复杂。首先要解决的就是操作对象的实例定位问题。即当如下访问控制出现时:“李厚强可以修改用户信息中的姓名,但不能修改用户信息中的身份证号”。很明显,现有的三维ACM已经不能满足要求了。 ACM中的操作对象之所有成为对象,是因为其具有以下两种特征:一是对象是数据的封装、二是对象本身包含对现实对象的抽象。数据的封装简化了数据处理,抽象使得对象的形式更统一、方法数量可控制。但是,当业务要求权限控制到对象的成员这一级别时,这样的封装和抽象无疑将屏蔽掉对象成员的权限敏感性。解决的方法有两种: 方法1:将对象的有权限敏感的成员也抽象为ACM中的对象 Operator Operate Method Object ――――――――――――――――――――――――――――――――― 李厚强 修改 用户信息 李厚强 修改 用户信息.姓名 李厚强 修改禁止 用户信息.身份证号 方法2:为ACM增加第四个维度――Object.Fields,操作对象属性。 Operator OperateMethod Object Object.Fields ―――――――――――――――――――――――――――――――――――― 李厚强 修改 用户信息 - 李厚强 修改 用户信息 姓名 李厚强 修改禁止(只能“读取”) 用户信息 身份证号 粗看,似乎方法1更具有通用性。但考虑到Object.Fields和Object之间的关系、以及其对OperateMethod的影响,问题并不这么简单。原因是,Object是业务对象的抽象,其对应的操作(OperateMethod维度)往往是业务功能操作(BusinessOperate);而Object.Fields所对应的操作往往只有“修改”和“读取”两种,或类似的数据操作(DataOperate),其余的操作控制往往由其所的Object的方法所决定。如:我们不可能独立于用户信息去孤立的删除姓名,而只能“修改”、“读取”。当我们要删除某个姓名时,往往是删除一个用户。
|
Object |
Object.Fields |
对应操作类别 |
Business Operate |
Data Operate |
备注 |
常见操作均为功能。如:CRUD 以及于对象相关的业务操作 |
通常只有“修改”和“读取”控制 |
所有,对于Object和Object.Fields的访问控制所对应的操作对象和操作方法完全不同,在业务系统中Object和Object.Fields所对应的ACM的被访问场景也完全不同。在考虑到权限合并、权限干涉等问题,更好的设计应该是将ACM视作四维,或者这样理解:将系统通用ACM分为两个三维的ACM,即双级ACM。分别控制Object的访问和Object.Fields的访问: Object ACM 和 FieldsACM 4、解决难点 4.1权限合并 双ACM可以很好的控制权限合并。访问Object时通过ObjectACM,访问Object.Fields时,将ObjectACM和FieldsACM进行合并操作,得到最终的访问控制。 4.2权限干涉 通过ObjectACM与FieldsACM的主从关系来控制权限干涉。ObjectACM为主ACM,当ACM禁止某操作时就不用在访问FieldsACM了。(当考虑Operator、OperateMethod后权限干涉情况更加复杂,将在下面加以讨论) 4.3维度管理 ACM实现的前提是各维度各自的统一管理。如:操作者应该可以统一管理,当ACM确定Operator元素后,可以准确的根据Operator元素确定起对应的用户、单位、角色。操作者的统一管理很直接,业务系统多有单位组织管理和用户管理系统。而操作方法和操作对象的统一管理在一般的业务系统中没有。为实现精确的访问控制,必须将所有的操作对象和操作方法项进行统一的管理。 5、模型测试 测试四维权限管理模型是适用性。 测试1 说明:业务系统简单功能权限管理的实现,即:对功能访问控制。 一个业务系统往往在UI层上表现为若干有组织的分类的功能访问入口(通常是一个分级菜单组),要求根据当前系统使用者的权限取得相对应的功能访问项目入口。这里,ACM完全胜任:
Operator |
OperateMethod |
Object |
Object.Fields |
User/Depart/Role |
访问* |
功能A入口(菜单项) |
- |
… |
… |
… |
… |
*:对于功能操作入口本身,只有“访问”一种方法。 撇开操作者(Operator)这一维度中可能产生的权限干涉问题以外,不会产生任何其他问题。 测试2: 说明:业务系统对其所管理信息(业务对象)的简单管理时的权限管理的实现,即:对业务对象的访问控制。 实例1:例如任何业务系统都会出现的用户管理,用户本身就是一种业务对象。当一个操作者对系统中“用户”对象进行操作时,访问控制模块将根据其权限对其操作进行“允许”或“禁止”。
Operator |
OperateMethod |
Object |
Object.Fields |
User/Depart/Role |
修改 |
User(“用户”业务对象) |
- |
User/Depart/Role |
读取 |
User(“用户”业务对象) |
- |
… |
… |
… |
… |
实例2:例如一个报表管理系统中的已经定义的“报表”,也是一种典型的业务对象。与常见的业务对象不同,“报表”除了常见的CRUD操作,还会有其对应的“提交”、“入历史库”等业务相关操作,即:Business Operate。
Operator |
OperateMethod |
Object |
Object.Fields |
User/Depart/Role |
修改 |
ReportSheet(“报表”业务对象) |
- |
User/Depart/Role |
读取 |
ReportSheet(“报表”业务对象) |
- |
… |
… |
… |
… |
User/Depart/Role |
提交 |
ReportSheet(“报表”业务对象) |
- |
User/Depart/Role |
入历史库 |
ReportSheet(“报表”业务对象) |
- |
… |
… |
… |
… |
*:业务对象的操作多是Business Operate 利用四维ACM,避免了将Object.Fields作为Object的子对象来处理,从而简化了处理权限干涉问题时的模型。 测试3: 同样的报表管理系统中的已经定义的“报表”,每个“报表”是作为一个“工件”来处理的。这种“报表”类似与MS Office 2003的智能文档:根据业务需求,“报表”中的每个“数据单元格”或简单控件都要求权限敏感。
Operator |
OperateMethod |
Object |
Object.Fields |
User/Depart/Role |
修改 |
ReportSheet(“报表”业务对象) |
单元格A |
User/Depart/Role |
读取 |
ReportSheet(“报表”业务对象) |
单元格B |
… |
… |
… |
… |
User/Depart/Role |
激活 |
ReportSheet(“报表”业务对象) |
按钮1 |
User/Depart/Role |
激活 |
ReportSheet(“报表”业务对象) |
按钮2 |
… |
… |
… |
… |
*:Object.Fields对应的操作多是Data Operate:对于单元格、数据项就是“修改”、“读取”;对于简单控件就是“可见”、“激活”。 **:此时的Object维被弱化,成为Object.Fields的索引项 由于对Object的ACM和对Object.Fields的ACM是分开的,便于处理权限干涉问题。如:根据业务需要,UserA具有对ReportSheetA的读取权限,但是但对ReportSheetA中的FieldsA不可读。这时利用算法根据ObjectACM和FieldsACM进行合并即可,不必将Field视作Object的成员来进行访问控制,更不用将Field视作Object的子对象。 6、实践指导 其实,这里用于测试的四个场景基本覆盖了报表系统的访问控制的情况。下面,以此作为业务标本,简要描述如何在具体业务系统中实现ACM的访问控制。 访问控制类 最先的思路是在一个业务系统中设立一个通用的ACM。这是自然而然的想法,因为有很多通用的规则判断操作、访问验证规则等是控制不同对象都需要的,所以利用面向对象的方法,可以将ACM的验证规则、操作等封装到对象中,便于业务系统中广泛复用。 在这里,将这种对象包含访问控制操作、验证规则的类,称作:访问控制类AccessController。 图1:系统中有访问控制要求的模块均调用AccessController类 以上模型非常简单,可操作性好。但很明显,各个模块要求的验证规则虽然具有相同的验证调用接口,但其验证规则各不相同。如果要强行将这些规则封装在同一个类中,并利用参数的变化来控制验证规则实例的调用,明显是对抗“组合爆炸”。每增加一个有访问控制要求的模块、或每增加一个验证规则,AccessController都会被增加一组方法,相关的控制参数也有可能有变化,不可避免的会出现“大类”和“长方法”,系统粒度分布不均匀。 利用接口设计改善。我们不知道一个业务系统中会有若干访问控制验证业务规则,分属于不同的访问控制模块,并且随着系统的升级或需求的变化,有可能会增加新的验证规则。用接口设计可以一定程度上改善这个问题。 图2:利用实现类来实现IAccessController接口, 各实现类具有相同的调用格式,不同的规则 改进后的模型可使得开发组在开发时,根据具体访问控制的要求编写不同的验证规则,但同时验证过程的代码外形又具有通用性。如图2演示,每个访问控制实现类都有IsValidate函数,接受“操作者”、“操作方法”、“操作对象”作为参数,并验证该操作的合法性。 提示细节是,IsValidate函数接受的参数也是接口,即:
public bool IsValidate (IOperator, // 操作者接口 IOperateMethod, // 操作方法接口 IAccessObject) // 操作对象接口 |
*:实际设计时可以考虑使用抽象类(Abstract Class)等来替代接口,但原理一致,都是要推迟实现部分,以获得良好的扩展性。 而为了配合这样模型,受权限访问控制的各要素(“操作者”、“操作方法”、“操作对象”)均需在构架时即接口化。在实现时,根据业务需求实现相应接口,再作为参数传入访问控制验证函数中。 以上只是初步想法,具体实现形式待定。 7、总结 以上分析仅用作讨论。完全的自我消遣,嘿嘿! 附录A: 对应第5节,模型测试各场景,利用分级的ACM实现业务需求的时序图,仅供参考: 测试1: 操作流程对象即激发访问的业务系统组成部分,这里可以理解为GUI用户界面,以及其中的简单控制。 测试2: 沿用以上时序图,模仿真实情况:FunctionA即是对某个ReportSheet的访问。这时FunctionA即是访问ReportSheetA的操作控制流程对象。 测试3: 对ReportSheetA中的FieldA作访问,利用FunctionA判断处理权限干涉问题,交并权限后再访问ReportSheetA和FieldA。 - end -
Beegee: 和我在一个产品开发中共事了半年的部门经理(其实是产品经理)告诉我可以离开项目组了。半年前,他委托我设计他的产品中的权限管理模块。于是,我用我贫瘠的大脑给他想了些方案。难得他还那么看得上,支持我实现了我的设计,当然也加了不少我不喜欢的东西。现在,却因为一些原因我要离开这个产品组了,这位经理也不准备对这个模块再作更多的投入了,于是我想我可以把我的这些的想法拿到我的Blog中了,算是自我消遣吧。^_^,也希望能够帮助其他程序员完善他们自己的设计,全当反面教材啦! 共两篇: 1.“ACM四维权限管理模型”(本文) 2.“权限管理与访问控制概要设计”
作者Blog: http://blog.csdn.net/beegee/
相关文章
Ant随笔:自动测试与数据准备 |
自我消遣之二:权限管理与访问控制概要设计 |
自我消遣之一:四维权限管理模型 |
每日构建+单元测试 |
Modify Your Codes with PMD(2) |
|