倘若需要在privilege上面加上constraints怎么办呢?这正是非常头痛的问题。
举例好像在oracle中,数据库本身为使用者已经加上了role,use,privilege的概念,可以根据role来确定某个特定用户可使用的table和field,但是复杂的系统常常会要求在field上增加row的限制。比如table中有两条record,a和b,user1可以访问a,user2可以访问b,那么上述的那些可能都不可以适用了吧。
这正是我们在项目开发中极其头痛的问题。
现在想到的办法就是每个business object都应该有自己的privilege和constraint,当访问这个object的user具备了相应的privilege和constraint时,便可以访问此对象,但是这样做的话,当constaint涉及到的内容非常多的话,会引起权限判断的响应很慢,而且最好在内存中处理。但是这是非常消耗内存的,这不是我们希望看到的。
各位有什么好的见解吗?
效率与安全往往是相对立的,过多的安全必然带来效率上的减速。
这是客观规律,在我能看到的地方,很难打破这条规律。

你觉得头痛,其实还有一点,就是你的模型还没有建好,没有完全弄清楚需求。当你看清楚了对象间的关系后,自然就会轻松下来

权限判断我认为一定要在内存中进行,千万别推后到数据库端,我个人认为在一些系统下,不适合过分依赖数据库系统的权限验证,J2EE也有自己的权限验证,但要在其上定制出自己的权限系统不是那么容易。

Iceant的观点很对。起初的模型建立后,权限关系在设计思路上不会太复杂。

"权限判断我认为一定要在内存中进行,千万别推后到数据库端"

我对这一句不是很理解。
一般比较常用的权限模型分两步:
认证与授权。

第一步,在用户填写了 login info 后,系统要识别该用户是谁。
一般来说,会记录下用户的一些信息,备后面用.
第二步,用户访问具体的 Resource 时,具体的系统会判断该用户在该系
统中的角色,这里就是授权。有权限的合法用户,才能使用资源

对于第一步认证,必要要进行 CRUD 的操作,如果你使用了数据库来做为存取介质,那么,肯定要进行数据库的操作。

第二步,看具体的系统设计,有可能还会需要数据库,也有可能就在内存中进行处理。

从数据库中取出权限放在权限类中,在内存中通过权限类来验证权限。我想这属于内存中处理。

jive中的在代理类中验证权限难道不好么?取出的Iterator要在代理类中过滤一遍,是不是很浪费内存?

Rep:回Banq
同意你的意见,我觉得这样做也可以:
应有如下表:
users 用户表
Module 应用程序模块表
Role 角色表
RolePower 权限开关表
SubRole 二级权限表

他们的对应关系如下:
Role.RoleID=Users.RoleID
RolePower.RolePowerID=Role.RoleID
RolePower.ModelID=Module.ModelID
SubRole.SubRoleID=Role.RoleID
SubRole.SubRoleID=Users.SubRoleID

在用户登录时只需要一个查询就可以搞定他可以进入到什么模块可以做什么?
select ModelID,ModelName,MenuTree,ExeName from Module
where MenuTree like @TreeID+'%'
and MenuTree <>@TreeID
and ModelID in (select ModelID from RolePower
where PositionID=(select PositionID from SysUsers where UserID=@UserName))

这是 Portal 的思想。
但是我有个疑问,如果有人知道系统中某些资源的入口,直接进入,
而不是通过 Portal 给定的入口,那么怎么控制好权限呢?

我使用 View 来控制权限。
在 View 的接口里,定义了 securityCheck() 方法,而且是访问视图的第一个方法。
跟着,实现了一个 ViewBase 的基类,所有的视图都从这个类衍生,
这样,我在ViewBase 里实现了最基本,最通用的权限检查逻辑,

不同的应用系统,可以根据自己的需求,重写 securityCheck() 方法,并在所有该系统的视图中重用该方法。这样,每次访问 View 都要判断权限(当然有办法可以加速这个过程,但是无论如何加速,这个过程始终是要影响效率的),速度会有影响。

正如我上面所说的,安全和效率在我能理解的世界里永远是对立的。

所以,要安全与效率,需要一个评估与平衡

你这个办法类似Jive的ForumFactory, FOrumFactory是外界访问论坛的唯一入口,ForumFactory通过实现Proxy模式的ForumProxyFactory才能真正访问到论坛资源,这是相当安全,但是我觉得使用动态Proxy更好,只要对所有资源的setXXX或getXXX方法进行监控就可以了。
关于权限系统,其重要性当然不言自明。看见大家的方案,有相当多的创意包含在里面。我的项目也有涉及到,以下说明的是我最近实现的方案(以及设计考量),与诸位共商榷。


前言:

权限是一个极其复杂的问题,但可以简单表述为:判断“who 对 what(which) 进行 how 的操作”的逻辑表达式是否为真。

针对不同的应用,需要根据项目的实际情况和具体架构,在维护性、灵活性、完整性等N多个方案之间比较权衡,选择符合的方案。


理解:

这个权限系统的设计,我主要考虑了这么几个方面:

直观,因为系统最终会由最终用户来维护,权限分配的直观和容易理解,显得比较重要,系统不辞劳苦的实现了组的继承,就是以为它足够直观。

简单,包括概念数量上的简单和意义上的简单,以及功能上的简单。想用一个权限系统解决所有的权限问题是不现实的。设计中将“定制”特点比较强的部分判断为业务逻辑,而将“通用”特点比较强的部分判断为权限逻辑就是基于这样的思路。

扩展,我在以前的项目中也实现过基于 Role 概念的权限系统,效果不太理想。这里之所以不采用 Role 的概念,就是因为它不易扩展。通常 Role 的设计方式意味着预先已经定好的一组权限,而,因为这样的“预先设计”,常常会鼓励程序员 hardcode 这些权限相关的部分。当需要重新定义 Role 时,扩展就会变得极为困难。而采用可继承的 Group 概念也可以支持权限的重新定义,但有效的避免了扩展方面的缺点。


名词:

下面两个名词极其重要,是整个设计问题边界定义的关键,或许我的理解与通常的理解不同,在此有必要特别澄清。

粗粒度:表示类别级,即,仅考虑对象的类别,不考虑对象的某个特定实例。比方,用户管理中,创建、删除,对所有的用户都一视同仁,并不区分操作的具体对象实例。

细粒度:表示实例级,即,需要考虑具体对象的实例,当然,细粒度是在考虑粗粒度的对象类别之后才再考虑特定实例。比方,合同管理中,列表、删除,需要区分该合同实例是否为当前用户所创建。


原则:

权限逻辑配合业务逻辑。即,权限系统以为业务逻辑提供服务为目标。纯粹纸面意义的权限系统,这里不予讨论。而且,相当多细粒度的权限问题极其独特不具通用意义,它们也可以被理解为是“业务逻辑”的一部分。比方,要求:“合同资源只能被它的创建者删除,与创建者同组的用户可以修改,所有的用户能够浏览”。这既可以认为是一个细粒度上的权限问题,也可以认为是一个细粒度上的业务逻辑问题。在这里我认为它是业务逻辑问题,在整个权限系统的架构设计之中不予过多考虑。当然,权限系统也必须要能够支持这样的控制判断。或者说,系统提供足够多但不是完全的控制能力。即,设计原则可以归结表述为:“系统只提供粗粒度的权限,细粒度的权限被认为是业务逻辑的职责”。

需要再次强调的是,这里表述的权限系统仅仅是一个“不完全”的权限系统,即,它不提供所有关于权限的问题的解决方法。它提供一个基础,并解决那些具有“共性”的(或者说粗粒度的)部分。在这个基础之上,根据“业务逻辑”的独特权限需求,编码实现细粒度的部分,才算完整。回到权限的问题公式,我的设计仅仅解决了 who + what + how 的问题,which 的权限问题被当作是业务逻辑。


概念:

User:用户。解决 who 的问题。
Group:组。权限分配的单位与载体。权限不考虑分配给特定的用户。组可以包括组(以实现权限的继承)。
Operate:操作。表明对 what 的 how 操作。


说明:

User

与大家的都一样,没什么好说的。

Group

与大家的类似,所不同的是,Group 要实现继承。即,在创建时必须要指定该 Group 的 Parent 是什么 Group 。在粗粒度控制上,可以认为,只要某用户直接或者间接的属于某个 Group 那么它就具备这个 Group 的所有操作许可。细粒度控制上,在业务逻辑的判断中,User 仅应关注其直接属于的 Group ,用来判断是否“同组”,间接的 Group 对权限的控制意义不大。试设想存在一个 All User 的 Group 是所有 Group 的祖先,这样的情形下,判断的结果不具备实际意义。

User 与 Group 是多对多的关系。即,一个 User 可以属于多个 Group 之中,一个 Group 可以包括多个 User 。

子 Group 与 父 Group 是多对一的关系。即,一个子 Group 只能有一个父 Group ,一个父 Group 可以包括多个子 Group 。


Operate

某种意义上类似于大家的 Resource + Privilege 概念,但,这里的 Resource 仅包括 Resource Type 不表示 Resource Instance。

Group 与 Operate 是多对多的关系。

各概念的关系图示如下:


User
|*
|
|* 1
Group---+
|* |* |
| +---+
|*
Operate


解释:

之所以将 Resource Type 和 Operate 绑定在一个概念里而不是分开建模再建立关联,是因为很多的 Operate 对于某 Type 的 Resource 才有意义。比方,发布操作对新闻对象才有意义,对用户对象则没有意义。

操作本身的意义也大大拓展,这里并非仅定义类 UNIX 的 RWX 三种操作(这样的定义对于文件系统是合理的,对于其他的应用领域或许就不是那么足够了),而是定义了 N 种具体的操作。比方,对于合同的创建操作、提交操作、检查冲突操作等。可以认为,操作概念对应于每一个商业方法。

其中,与具体用户身份相关的操作既可以定义在操作的业务逻辑之中,也可以定义在操作级别。比方,创建者的浏览视图与普通用户的浏览视图要求内容不同。你既可以在外部定义两个操作方法,也可以在一个操作方法的内部根据具体逻辑进行处理。具体应用哪一种方式应依据实际情况处理。

这样的架构,应能满足绝大部分粗粒度权限控制的功能需要。但是,除了粗粒度权限,无可否认,系统中必然还会包括无数对具体 Instance 的细粒度权限。这些问题,在这里被认为是业务逻辑的职责。

一方面,细粒度的权限判断必须要在资源上建模权限分配的支持信息才可能得以实现。比方,如果要求创建者和普通用户看到不同的信息内容,那么,资源本身应该有其创建者的信息。如同 Unix 的每一个文件(资源),都定义了对 Owner, Group, All 的不同操作信息。

另一方面,细粒度的权限判断具有相当大的业务逻辑相关性。对不同的业务逻辑,常常意味着截然不同的权限原则和方式。相比之下,粗粒度的权限更具通用性,将其实现为一个架构,更有重用价值;而将细粒度的判断方式与逻辑实现为一个架构级别的东西就显得不是那么的有必要了,而用代码级别来实现就显得更为灵活一些。


结语:

希望我的文字表述清楚,希望我的方案能激起大家讨论研究的兴趣。

TO: Banq

^_^ 我想,还是不一样的!

按照您的描述,Jive 通过统一入口来控制访问。
但是我不同,我是在每个 View 里面控制。
如果按照纯 JSP 的方式来理解,就是在每个 JSP 文件里写
授权的代码(注意我说的是授权,并不包括认证)
对于纯 JSP 来说,这被认为是很不好的方式。
但是对于我使用的框架来说,这确非常顺理成章.

而且从我理解的架构上来说,这样可能更好一些。
因为,每个视图就是一个对象,每个视图对象都有防止越权访问的能力。
这不是更加合乎 OO 的思想吗?

你们讨论的好乱哦。
我觉得好像有几种管理的办法,其实都是可以说的过去的。
各个系统都有不一样的要求,尺寸各有长短!
不过要提醒大家(教训):用户的需求一定要掌握好,要不就因为这个用户管理,权限管理累死你。。。呵呵:)本人在痛苦ing……
不过用户到角色之间的对应关系是怎么设定的?我的用户权限系统是用户有一些可以比较的属性数据,然后指定角色的划分原则,不过这样每次都需要重新计算角色的成员,给系统的压力比较大,大家有什么好意见?
谢谢。
我认为角色应该属于部门或模块
有理!pattern不是万金油。本人有时就是太注重模式了,结果实现时发现无法完全按照模式实现。