查看文章 |
[转贴]权限系统设计 -1 初步和实现方案
2007-04-16 9:41
一、概要通常,需要单独的权限系统是解决授权的管理和维护,再分配等难题,不针对开发而言。
系统架构目标:在易于理解和管理,开发的前提下,满足绝大部分粗粒度和细粒度权限控制的功能需要。
除了粗粒度权限,系统中必然还会包括无数对具体Instance的细粒度权限。这些问题,被留给对框架的扩展方法来解决,这样的考虑基于以下两点:
1、细粒度的权限判断必须要在资源上获取权限分配的支持的上下文信息才可能得以实现。 2、细粒度的权限常常具有相当大的业务逻辑相关性。对不同的业务逻辑,常常意味着完全不同的权限判定原则和策略。相比之下,粗粒度的权限更具通用性,将其实现为一个架构,更有重用价值;而将细粒度的权限判断实现为一个架构级别的东西就显得繁琐,增加架构的复杂性。而且不是那么的有必要,用定制的代码来实现就更简洁,更灵活。否则会变成各种逻辑代码的堆砌。
比如,product post数量的控制,这种一般要知道用户个性化的信息,付钱数量到数据库中查找最高数量,还要知道此用户已经有多少产品等,规则不具备通用性和重用性,
所以细粒度控制不应该放在权限架构层来解决。实例级的细粒度权限的解决方案就是将它转化为粗粒度权限,这样我们权限客户端就变得很简单了。
名词解释:
粗粒度权限 :一般可以通过配置文件来授权,授权只有真假,没有多少之分,不需要上下文的支持。
不消耗资源的。
逻辑表达式:判断“Who对What(Which)进行How的操作”的逻辑表达式是否为真。
别名:静态授权、类级授权
例如:发布Offer.
细粒度权限:不能通过配置文件等表达,需要特定上下文的支持.
逻辑表达式:判断“When(Where)的时候,Who对What(Which)进行How的操作”的逻 辑表达式是否为真。
别名:动态授权、实例级授权
例如:发布Product.
设计原则 :
框架只提供粗粒度的权限。
细粒度的权限也需要集中管理和维护
细粒度的权限通过定制的扩展代码将细粒度转化为粗粒度授权。
二、权限系统的设计权限往往是一个极其复杂的问题, 设计权限系统第一个要解决的问题就是什么样的行为是需要权限控制,什么样的是业务方法。他们之间本来是没有明确的区分,任何权限从某种角度上说可以是一种业务方法。为了以后管理和开发方面我们从概念上需要将权限和业务明确划分清楚,指导开发。
权限控制行为: 对What(Which)进行How的操作需要区分Who,具有Who身份差异性和可替换性。
我们将此类操作作为权限。
特点: 可以收回也可以分配的,具有一定的抽象级别。
消耗资源,行为结果具备一些持久性的影响。
业务逻辑行为: 对What(Which)进行How的操作的时候与Who的身份无关或者具有Who身份差异性但
是不具有可替换性。如专门为TP定制的推广等
特点: 不能抽象和共享,很难回收和分配。
不消耗资源,不产生持久性。
现实中也存在某一时期行为是业务逻辑,最后演变成权限控制,或者相反的过程。
1、粗粒度权限设计
根据我们网站的特征,我们决定采用自主型访问控制方法,操作给予访问控制列表。每一个用户通过角色获得一组权限集合,权限系统的功能是验证用户申请的权限(集合)是否在这个集合当中,即申请的权限(集合)是否投影在用户拥有的权限集合,换句话说:只要某Member直接或者间接的属于某个Role那么它就具备这个Role的所有权限许可。
一个自主型访问控制方法的权限系统包括以下几个部分:角色、权限、访问控制表、
l 权限
描述一个权限可以通过以下几个要素说明:
类型(class):
名称(name):
动作(actions):
掩码(mask):
属性:
具体权限Example:
1、Offer
类型(class):com.yangjs.secutiry. permissions. OfferPermission
名称(name):如:offer.* ,offer.buyer.* ,offer.seller.tp
动作(actions): brower_detail ,post,repost,……
掩码(mask):0x1,0x2,0x4…..
属性: 无
2、product
类型(class):com.yangjs.secutiry. permissions.ProductPermission
名称(name):
动作(actions): brower_detail,post,repost,
掩码(mask):
属性:
3、Company
.…………..
l 存取控制器(yangjs--acl.xml)配置
存取控制项(ACE):角色到权限的映射集合,表示某个角色可以在某些资源上执行某些动作
它们之间通过role关联(继承),ACE之间产生包含关系。
存取控制列表(ACL):ACE的集合。
我们的存取控制器(ACL)是通过一个xml的配置文件说明,存取控制列表由多个存取控制项(ACE)来描述。配置方式
<!--=============================== Role ============================-->
<acl-entry role="NewBuyer" parent="NonMember">
<permissions>
<permission
name="offer.buyer.*"
type="com.yangjs.security.permissions.OfferPermission"
actions="post,repost">
</permission>
<permission
name="offer.buyer.open"
type="com.yangjs.security.permissions.OfferPermission"
actions="brower_detail">
</permission>
<permission
name="offer.seller.*"
type="com.yangjs.security.permissions.OfferPermission"
actions="brower_detail">
</permission>
</permissions>
</acl-entry>
<!--=============================== Role ============================-->
<acl-entry role="FreeMember" parent="NewBuyer">
<permissions>
<permission
name="offer.buyer.*"
type="com.yangjs.security.permissions.OfferPermission"
actions="post">
</permission>
</permissions>
</acl-entry>
使用方法以post offer作为例子,从用户点击post offer开始
逻辑
1、判断用户是否登陆
2、用户登陆完成后,在用户cookie中存放身份和角色标记
3、由于post offer需要授权,程序向系统申请权限,如果通过,操作可以,否则,通知用户无权。
代码:
try {
MemberType mt = . . . . ;
String actions = OfferActions.POST.getName();
OfferPermission bo =
new OfferPermission("offer.buyer", OfferActions.POST.getName());
AccessController.checkPermission(mt, bo);
} catch (AccessControlException e) {
// 没有buyer offer的post权限,处理…………………………
}
2、细粒度权限设计
细粒度授权需要上下文的支持,而且每个权限控制的上下问题都不一样,这由相关的业务逻辑决定,而且此类授权一般变化较快,应此需要将强的可维护性和扩展性,支持变化,但又不能够太复杂,否则缺乏可执行性。虽然此类权限个性化较强,我们仍然可以总结出很多共性:
1. 几乎所有的授权需要会员的角色和ID.
2. 特定的上下文几乎都同用户在我们网站资源使用情况相关,如用户scott发布了多少Product.
我们将此类信息称为MemberState 即:Member角色以及资源使用情况和当前状态。大部分信息我们在用户登陆的时候已经。获得。授权贯穿Web层和Biz层,因此我们的登陆要独立于Web端。因此上下文我们可以用MemberState结合其他来抽象。
关于上下文的维护问题,我们不可能将MemberState此类参数在Web层和Biz层来回传递,更加不能在需要授权的地方都加上一个这样的方法参数,这样不太现实。其次如果在授权的地方再从数据库中取一次这样虽然能够解决部分问题(不能解决MemberId的传递),这样效率太低,不能接受。
解决方法就是将此类信息cache起来,用的时候再去取,由于此类信息具有非常高的并发性,对线程安全较高,因此我们决定将此类信息放入一个线程上下文的内存cache中。此外我们由于引入cache,就需要解决所有cache共有的维护性问题。
Cache的生命周期:用户的一次请求,属于线程级,用户请求线程结束,Cache结束。
Cache的更新:当上下文信息发生变化是需要及时更新Cache,这是一个不可避免的步骤。
Cache丢失:发生在如系统down机,线程崩溃,内存溢出等等,对用户来说就是当前请求突然中断。
当用户重新发送请求,我们的系统就需要重新验证用户,此时我们可以更新Cache解
决丢失问题。
Cache的清理:这个实现就是当用户请求结束,返回应答的时候清理,可以通过Filter实现,比较简单。
以上是相关的原理部分,我们看看系统地实现:
实现:
线程上下文的cache
实现类:com.yangjs.commons.cache.ThreadContextCache:
public class ThreadContextCache {
public static Map asMap();
public static boolean containsKey(Object key);
public static boolean containsValue(Object key);
public static Object get(Object key);
public static void put(Object key, Object value);
public static Object remove(Object key);
public static void clean();
public static int size() ;
public static void destroy()
}
客户端用法:
如:Product Post细粒度权限:
public static boolean hasPostPermission(String name) {
MemberState ms = (MemberState)ThreadContextCache.get(GlobalConstants.MEMBER_STATE_KEY);
if(ms == null){
throw new IllegalStateException("Thread context the value memberState is null.");
}
ProductPermission pp = new ProductPermission(name, ProductActions.POST.getName());
try {
AccessController.checkPermission(ms.getMemberType(), pp);
} catch (AccessControlException ace) {
return false;
}
int maxPostNumber = getMaxPostNumber(ms.getMemberId());
int postNumber = getPostNumber(ms.getMemberId());
return postNumber<maxPostNumber;
}
三、相关类的介绍和维护 User其实就是我们的会员账号。我们的关键问题是Group的划分和粒度问题,是不是需要将整个member库作为我们的唯一Group?
Role就是一个拥有一组权限的集合,是一个抽象的概念。
我们使用权限系统第一个是确认是不是我们的Member会员,即使不是在Group中,然后分配给这个User响应的角色。我们的权限系统就是根据这些角色完成授权。我们的会员只有被当作某种角色才会获得权限,这些思想和基于角色访问控制(role-based access control,RBAC)基本一致。
User的粒度问题,以及它们之间的关系。从大的方面看我们分为Free,TP,GS,CS 或者buyer,seller等。
权限行为action的维护和管理
权限name的规则,通配符的使用方法
resource-control.properties
系统对特殊性的支持。
根据权限name查找所有匹配权限的操作集合,判断action是否在集合中。
三、扩展性和灵活性扩展性和灵活性需求的支持:
1、增加一种用户类型(角色)
方法:修改配置文件yangjs-acl.xml,添加一条ACE即可。
2、授权和管理现有权限,重新分配权限等
方法:修改配置文件yangjs-acl.xml中相关的ACE
3、添加一种新的权限类型
方法:需要开发一个继承com.yangjs.secutity.yangjsPermission的权限类,开发可参照其他类方法
在 yangjs-acl.xml中进行此项权限的分配和管理
4、为某一种权限添加一种行为 |
最近读者:

