深入讨论通用权限组件的理论和设计实现。

08-02-03 johnnylzb
本人最近正在为公司的多个项目(包括未来项目)做通用的权限组件,在本论坛上看到”dunel”大侠的一个帖子 http://www.jdon.com/jivejdon/thread/13450.html,然后才注册并发表此 话题,欢迎大家耐心阅读并指正。

目前已经发布了一个版本并供几个项目使用,先简单介绍一下组件的情况:

1.模式:建立在RBAC理论技术上的权限模式

2.技术:是以Java编写的一个组件(计划在下一个版本做成一个框架)

3.结构:包括两部分:

(A)权限配置管理平台,一个Web应用(即一个war包),用于注册受控资源,管理角色,和授权(把角色指派给宿主系统的用户),本平台是可选的

(B)权限服务组件,一个嵌入式组件(即一个jar包),提供访问控制服务和权限配置服务(后者供宿主系统通过接口调用实现权限配置管理,可以代替权限配置管理平台)

4.实现机制:权限相关数据与宿主系统的数据逻辑上式独立的,宿主系统通过嵌入权限组件,本地调用组件提供的相关服务接口实现权限配置管理和访问控制,组件提供四种服务:

(A)授权服务:用户访问宿主系统的受控资源时,宿主系统把用户ID和被访问资源ID传递到授权服务接口,授权服务接口返回是否可以访问的结果信息,宿主系统可以一次加载用户的所有权限信息,也可以在每次用户访问时才调用授权服务接口。

(B)实体管理服务:提供受控资源(实体)的增、删、改、查等管理服务。

(C)角色管理服务:提供角色的增、删改、查管理服务和为角色配置受控资源的服务

(D)授权管理服务:提供为宿主系统用户指派、移除角色的服务。

宿主系统可以把UI相关的实体名以URI来注册,权限组件提供默认的Filter进行拦截,对API的实体名以API对应的方法名的全限定名进行注册,权限组件提供默认的Interceptor以AOP的方式进行拦截,这样,宿主系统就不需要在业务层和页面层编写与权限控制相关的代码,权限这个功能编程了一个可以切入和移除的Aspect。

5.功能范围:目前只能控制功能权限,数据权限控制还没实现。

    

5
johnnylzb
2008-02-03 15:50
在本论坛看到了各位高手的一些关于权限模型和实现的讨论,觉得受益匪浅,所以本人也想针对权限控制提出一些本人的观点和针对一些困难请求解决方案,我的帖子将围绕以下几个方面讨论:

RBAC模型和相关概念

功能权限和数据权限

权限、角色与组织机构、用户之间的关系

1. RBAC模型和相关概念(以下观点是本人在理解RBAC模型之后结合个人意见的观点,如不合理,请指出并欢迎讨论)

1.1 术语定义:

受控资源:系统需要进行访问控制的资源,包括功能性资源和数据性资源,所以受控资源分为功能实体和业务实体:

(A)功能实体:从抽象角度来看,用户(不一定是人,也可以系统)使用系统只有两种途径:通过UI访问,如:按钮、页面、菜单等;通过API访问,如服务接口,DAO接口。经过这样的定义,对功能实体的操作就可以抽象成只有一种:访问。

(B)业务实体:即宿主业务系统相关的领域模型对象,如房地产交易系统的客户、楼盘、房间、合同等。对于业务实体,其操作可以抽象成四种:增加、删除、修改、读取。

操作行为:对受控资源的操作类型的抽象,对功能实体,操作行为只有“访问”,对业务实体,操作行为有“增加”、“删除”、“修改”、“读取”

权限:权限是实体+操作的组合,即“对‘什么资源’执行‘什么操作’”,因此,每个功能实体只能有一种权限,但每个业务实体,可以有最多四种权限。

角色:角色抽象上跟权限是同一概念,因为角色是反映用户可执行的权限,角色实际上是权限集,因为“人”会频繁变动,但“角色”却很少变动,所以才需要引入“角色”这个概念。

1.2 关系概念

实体之间的关系:实体与实体之间可以表现为从属关系和关联关系。

(A)从属关系,实体可以拥有一个父结点,多个子结点,拥有子结点权限的前提是必须拥有父结点权限,例如“楼盘信息”页面,拥有“查询楼盘”、“修改楼盘”两个按钮,那么“楼盘信息”页面这个功能实体就是“查询楼盘”和“修改楼盘”两个按钮功能实体的父结点,用户只有在拥有“楼盘信息”页面的访问权的前提下,才可能拥有“查询楼盘”和“修改楼盘”两个按钮的操作权。

(B)关联关系:实体之间的松散耦合关系,如A页面内嵌了C页面,B页面也内嵌了C页面,C既不属于A,也不属于B,这种情况,A与C、B与C之间就构成了关联关系。

角色与实体之间的关系:角色与实体之间存在多对多关系

角色之间的关系:扩展关系与排斥关系,建立这些关系主要是方便管理,对于正向授权,可以使用扩展关系,如角色A拥有1、2、3的权限,角色B比角色A多拥有4的权限,则角色B可以扩展角色A,然后为它指派4;对于反向授权,可以使用排斥关系,例子跟前者相反。对于这种关系还可以进一步扩展,就是一个角色可以扩展自多个角色,也可以排斥多个角色。根据实际情况,扩展关系比较常用。

1.3 存在争议

【讨论点1】其实对“业务实体”的操作最终都会表现为一种功能,如:对“合同”执行“修改”操作,可以被定位为“修改合同服务”这样一个功能,以业务接口的方式暴露出来,因为一般的业务系统设计中,业务系统并不会把纯数据的操作(即DAO)直接暴露给外界使用,而是把业务接口暴露给用户使用,用户只能通过业务接口对数据进行操作,不能直接操作一个业务对象。理论上,一个业务操作可能对应多于一个的业务实体的多于一个的操作,举个例子,删除一个可售楼盘信息这个业务,包括了多个业务实体操作:可售楼盘+删除、楼盘的房间+删除、销售信息+修改。所以,从更高一层的抽象看待“受控资源”,它可以全部被定义为功能实体,而对受控资源的“操作”,则都可以被抽象成“访问”。

【讨论点2】基于RBAC的理解模型,还应不应该允许直接把权限分配给用户,从本人的角度来看,由于权限对于大部分系统都是一个Aspect的问题,因此权限这个Aspect是不应该包括用户的,即权限模块的数据模型只有实体、角色及其之间的关系,用户作为另外一个Aspect(可以做成一个统一用户管理模块),如果只允许把角色与用户建立关系,不允许用户之间指派权限,则从系统角度来看,“权限控制”与“用户管理”作为业务系统的两个Aspect模块,他们之间的联系就会更加简单和清晰,就是“权限.角色”-“用户”。但另外一个问题是,很多时候,管理人员需要为某些特定的用户在他拥有的角色上根据实际需要分配多若干个权限,如果都需求定义角色,就会出现角色泛滥,不便管理了。这是从系统设计角度与现实情况角度相矛盾的地方。

2.功能权限和数据权限

2.1 概念定义

功能权限:在第1点已经阐述过,用户与业务系统进行交流,一般是面向服务的,即业务系统会把服务抽象成一个个功能点暴露给用户,功能权限实际上就是决定用户能否使用系统提供的功能点的问题,即“‘谁’对‘什么资源’进行‘什么操作’”(而根据上面的第1点的讨论点1,权限可以被简化为对功能实体的访问操作,即“‘谁’访问‘什么功能实体’”)。

数据权限:关于这个概念,有多种说法,有人认为对一个对象进行不同的操作就表现为数据权限,比如对“论坛帖子”进行“阅读”和“修改”、“删除”等属于数据权限,但本人认为(结合第1点的讨论点1),这归根结底还是功能权限(或者说,可以被定义为功能权限)。本人理解的数据权限,是指基于特定用户的权限控制,即“‘谁’访问‘什么资源’当中的‘哪些资源’”的问题,举个例子:分论坛A的版主与分论坛B的版主拥有同样的角色“版主”,即他们的功能权限是一致的,但A版主只能管理A论坛的帖子,B版主只能管理B论坛的帖子,这时,RBAC就不能解决这类权限问题,这种情况,角色就需要与组织结构有所联系了。进一步,更复杂的情况:高级经理能审批50万以上的合同,中级经理只能审批50万以下的合同,这就更加需要引入“规则”进行权限控制了。

2.2 权限组件是否(能否)把数据权限控制也纳入它的功能范围

本人对这点非常困惑,但经过各种权衡,本人设计的权限组件还是“暂时”不把数据权限纳入通用权限组件的范畴,理据如下:

(A)功能需求上的考虑:“权限”是一个很大的概念,也和模糊,功能性权限无可非议,是纯权限的功能,但对于如上述2.1所述两个例子,就存在角度问题,从权限功能角度看,它们属于权限的功能需求,但从业务的角度看,很明显,上述两个例子都属于业务规则,他们的权限会根据业务的变化而变化的,例如论坛的分版主原来只可以管理本版的数据,但需求改变了,他也可以管理其他版的数据;对于第二个例子,变化更加难于控制,可能需要上要求高级经理可以审批的金额数变化了,可能因为经理的级别变化了,甚至可能会加入更多的规则。这两个例子,后者更加偏向于业务规则,本人觉得这种于业务规则紧密集合的“权限”,不应归纳到“权限组件”去实现,但对于第一个例子,可以通过引入组织机构得到一定程度的解决,但这样也引出了一个新的问题:权限于组织机构的关系,对于业务系统来说,两者应该是两个独立的Aspect,还是应该整合在一起呢?这个问题在第3点进行讨论。

(B)系统设计上的考虑:系统设计的原则是功能独立单一,结构清晰,依赖耦合低,灵活和可扩展的。因此,我们目前主要的业务系统架构是:展示层-业务层-数据层,把所有业务逻辑集中在“业务层”统一管理,这样的好处有:

功能单一:各层负责各层的功能,只要是面向接口通讯,每一层的修改都是独立的,而且因为功能独立,也便于维护;

业务封装:所有业务被封装在业务层,使业务可以被灵活的组合和重用,业务与展示也分离了;

安全稳定:所有业务处理被封装到业务层中,无论外界传递一些什么破坏性数据过来,业务层都只做它该做的事,不会做它不该做的事情,例如用户用户系统的“修改用户基本信息”服务,但他尝试把密码也修改传递过来,而“修改用户基本信息”这一服务把所有业务逻辑封装了,它不会受外界影响,接收到用户信息对象时,即使密码被改变了,由于它的业务逻辑不处理密码,密码也不会被修改被持久化到数据库。

数据层独立:数据持久化动作交给数据层(通常是DAO)处理,DAO不管业务,把所有数据的访问都抽象为“增”、“删”、“改”、“查”,DAO可以被所有业务模块公用,也可以进行更换,例如因为性能或成本需要更换持久层ORM框架、更好数据库(更准确来说是数据源)。

而“权限”,这作为一个“横切面”的Aspect,根据AOP设计理论,是应该从系统的三层结构中分离开来的,三层架构是系统的一个“维度”,权限又是另外一个“维度”,彼此之间只有连接点(JoinPoint),没有耦合,彼此不可见。从这个角度来看,如果把与业务逻辑相关的所谓“权限”交给权限组件去做,则一来业务系统对权限组件依赖变成“硬性依赖”,二来业务逻辑被分散管理了。作为系统的设计人员,你会希望你的开发人员在修改业务逻辑的时候,需要从业务层和权限Aspect把零散的业务逻辑收集并理解吗?一旦将来系统的权限控制需求发生改变,需要更换权限组件,或者需要以硬件的方式来进行访问控制,你是不得不向上级领导申请人月资源去重新编写你的业务逻辑了吧?

(C)重技术实现角度考虑,如果需要把这类与业务规则有关系的数据权限控制交给权限组件实现,那么权限组件就需要设计成一个框架,提供标准的接口供业务系统根据不同的业务规则实现不同的访问控制策略,但需要抽象的定义一套能适应各种业务规则的接口(及其传递的参数,返回的结果),并不是一件十分容易的事情(当然,并不是不可能)。

(未完待续。。。)

[该贴被johnnylzb于2008-02-03 16:14修改过]

banq
2008-02-03 19:50
非常清晰的思路,与我思路基本一致,也指出了一些待讨论的地方,比较客观。JiveJdon3的权限思路也是基本按照这种思路设计的。

>权限组件是否(能否)把数据权限控制也纳入它的功能范围

我个人也认为数据权限属于业务性质范围,所以,不应有纳入通用的权限组件,所以在JiveJdon3中,专门做一个ForumMessageShell来对数据权限进行实现,而且随着业务变化,可能涉及修改面比较多,因此使用Proxy代理模式。

这里就体现模式的作用:不能用框架(通用权限组件)实现的,在微观上我们有模式来,总体目标就是将权限尽量和业务功能分离,框架能够实现最大限度分离,框架无法发挥作用的,对于数据权限这样又属于业务,又区别其他特定业务功能的,就使用模式对付它。所以,模式和框架是设计人员最常用的两个武器(需要进阶的程序员必须学好这两个常用武器)。

权限这个问题在本站自开站以来一直在讨论,复杂主要在分析和设计两个方面,分析方面我们需要理解RBAC;在设计实现上,我们需要AOP框架和模式,所以,权限问题的解决能够考验一个程序员的全面素质。

所幸的是,在2007年即将过去,2008年春节来临之际,终于看到有人完整地分析设计了权限问题,可贺啊。

johnnylzb
2008-02-04 09:32
谢谢你的回复,很久就知道J道,以前水平太低,对于你的文章我读不太懂,现在参与Java开发两年了,有点心得,才敢在这里发言,其实我还有很多其他方面(设计方面,编码方面)的心得,希望以后多交流

>我个人也认为数据权限属于业务性质范围,所以,不应有纳入通用的权限组件,所以在JiveJdon3中,专门做一个ForumMessageShell来对数据权限进行实现,而且随着业务变化,可能涉及修改面比较多,因此使用Proxy代理模式。

请问这句话如何理解呢?如何使用Proxy模式呢?还有,针对Proxy,我有一点迷惑,由于我的设计是权限组件和用户管理组件都是宿主系统Aspect方面的问题,而我的权限组件是依赖于用户组件的(通过向用户组件传递宿主系统标识,获取该宿主系统的用户列表,用于把用户与角色进行绑定,即授权),在我设计权限组件的时候,领导还没有详细考虑统一用户管理组件的问题,于是一个同事就用很短时间写了一个提供用户CRUD的组件,我当时在想,这个组件是不稳定的,不能直接使用,于是我就为权限组件写多了一个模块(com.***.***.proxy.***),这个Proxy的作用是为权限组件提供足够的用于与用户组件打交道的服务接口(权限组件并不需要增、删、改,只需要查),并把用户组件返回的用户DO转换成权限组件自定义的用户DO,这样做的目的是,用户组件不稳定,将来肯定会有变化(说不定由本人负责设计),为了屏蔽这些不稳定因素,避免因为用户组件重新设计而影响权限组件,所以设计了一个Proxy来做“中介”,将来用户组件变化,只需要集中修改Proxy就行。我的这个问题可能是一个“文字问题”,究竟我使用的这种模式,是代理模式,还是适配器模式呢?

另外,我的讨论话题还没完,其实我还想讨论:究竟“权限”与“组织架构”是否应该设计在一起,还是应该分开,以及角色、用户、组织机构之间的关系问题,不过我暂时还没有想清楚如何条理的表达我的看法,所以还没写出来而已。

banq
2008-02-05 11:04
我讲proxy主要是指数据权限方面,因为数据其实就是业务对象,围绕业务对象有其特定的业务操作,比如订单操作,那么对于当前这个订单是只能被创建者操作这样的权限,就依靠权限代理来做。

代理模式和装饰器模式有一些区别,可在本站查询到,实际应用中我们不必太在意这些区别。

猜你喜欢
3Go 1 2 3 下一页