权限控制

在软件系统中,权限指的是系统用户对系统对象的执行某个操作的权限。

一、权限受哪些因素影响

图1 对象权限相关的因素

从权限的定义可以知道,权限与系统用户、系统对象有关,一般情况下系统用户不直接与权限发生关联,而是通过角色来间接关联。权限的相关因素可能有:

1. 角色授权(权限表)

例如用户A授予角色B对系统对象C的读权限。

2. 特殊角色(如管理员)对某些系统对象的类别有特殊的权限

例如系统管理员对系统中所有的对象都有全部权限。有时候不是所有的对象,而是某个类别的对象,如用户管理员对用户对象有全部权限,但对别的对象并没有什么特殊的权限。

3. 系统对象的内部状态或属性

例如文件的所有者对该文件有全部权限、文件被某个用户锁定编辑的时候仅该用户有修改的权限。

二、权限机制的实现

图2系统对象部分的类图

在系统对象部分,主要是处理与系统对象关系较为密切的权限判断,如权限表(不同的系统对象可能有不同的权限表,所以放在这里处理比放在角色部分好),还有一些与系统内部状态或属性相关的权限检查(因为不同的系统对象与权限相关的内部状态和属性都可能不一样,所以应该在这里处理。如果是比较通用的权限检查,例如检查系统对象与角色的Owner关系,则可以作为一个外部PermissionCheck类;如果是专用的或者是对系统不公开的内部状态或属性的权限检查,可以考虑作为内部类)。这里的PermissionCheck是采用策略模式来处理权限问题,这里的权限机制没有强制要求一定要采用该模式,系统对象完全可以不依赖任何PermissionCheck来处理权限。使用PermissionCheck的好处是简化系统对象,还可以实现一些通用的PermissionCheck以达到重用的目的,PermissionTable也是PermissionCheck的一个实现,基本上可以在所有系统对象中使用。

图3 角色部分的类图

角色部分的权限机制是基于以下几点:一是对系统对象的权限分配是基于角色的;二是每个系统用户都对应一个相应的专有的角色(这种角色可以不参与授权,但在权限检查时代表该用户,以便系统对象判断自身与该系统用户的关系)。系统用户在这里的主要职责是找到自己属于哪些角色,并请求这些角色判断对系统对象的权限,并将这些权限组合。由于企业组织结构图的复杂性和易变性,将这个组合角色权限的职责放在角色部分比放在系统对象部分要好一些,一旦企业组织结构图发生变化,不会影响到系统对象部分(另外有的系统对用户分类为只读和正常两类,组合权限也必须考虑这个,也是放在系统用户里处理比较合理)。每个角色除了要请求系统对象判断权限外,还要处理与角色相关的特殊权限,例如系统管理员角色、文档管理员角色等

图4显示了一个检查系统用户user对系统对象systemObject是否有权限类型为permissionType的权限的协作图。

图4 检查权限的协作图

图4显示了一个检查系统用户user对系统对象systemObject是否有权限类型为permissionType的权限的协作图。

基于java的权限控制系统设计

一、概要


通常,需要单独的权限系统是解决授权的管理和维护,再分配等难题,不针对开发而言。


系统架构目标:在易于理解和管理,开发的前提下,满足绝大部分粗粒度和细粒度权限控制的功能需要。


除了粗粒度权限,系统中必然还会包括无数对具体Instance的细粒度权限。这些问题,被留给对框架的扩展方法来解决,这样的考虑基于以下两点:
1、细粒度的权限判断必须要在资源上获取权限分配的支持的上下文信息才可能得以实现。


2、细粒度的权限常常具有相当大的业务逻辑相关性。对不同的业务逻辑,常常意味着完全不同的权限判定原则和策略。相比之下,粗粒度的权限更具通用性,将其实现为一个架构,更有重用价值;而将细粒度的权限判断实现为一个架构级别的东西就显得繁琐,增加架构的复杂性。而且不是那么的有必要,用定制的代码来实现就更简洁,更灵活。否则会变成各种逻辑代码的堆砌。


比如,product post数量的控制,这种一般要知道用户个性化的信息,付钱数量到数据库中查找最高数量,还要知道此用户已经有多少产品等,规则不具备通用性和重用性,


   所以细粒度控制不应该放在权限架构层来解决。实例级的细粒度权限的解决方案就是将它转化为粗粒度权限,这样我们权限客户端就变得很简单了。


名词解释:


    粗粒度权限 :一般可以通过配置文件来授权,授权只有真假,没有多少之分,不需要上下文的支持。


    不消耗资源的。


    逻辑表达式:判断“Who对What(Which)进行How的操作”的逻辑表达式是否为真。


    别名:静态授权、类级授权


细粒度权限:不能通过配置文件等表达,需要特定上下文的支持.


    逻辑表达式:判断“When(Where)的时候,Who对What(Which)进行How的操作”的逻辑表达式是否为真。


    别名:动态授权、实例级授权


设计原则 :


框架只提供粗粒度的权限。


细粒度的权限也需要集中管理和维护


细粒度的权限通过定制的扩展代码将细粒度转化为粗粒度授权。


二、权限系统的设计


权限往往是一个极其复杂的问题, 设计权限系统第一个要解决的问题就是什么样的行为是需要权限控制,什么样的是业务方法。他们之间本来是没有明确的区分,任何权限从某种角度上说可以是一种业务方法。为了以后管理和开发方面我们从概念上需要将权限和业务明确划分清楚,指导开发。


权限控制行为: 对What(Which)进行How的操作需要区分Who,具有Who身份差异性和可替换性。 我们将此类操作作为权限。


     特点: 可以收回也可以分配的,具有一定的抽象级别。       消耗资源,行为结果具备一些持久性的影响。


业务逻辑行为: 对What(Which)进行How的操作的时候与Who的身份无关或者具有Who身份差异性但             是不具有可替换性。


    特点: 不能抽象和共享,很难回收和分配。不消耗资源,不产生持久性。现实中也存在某一时期行为是业务逻辑,最后演变成权限控制,或者相反的过程。


1、粗粒度权限设计


       采用自主型访问控制方法,操作给予访问控制列表。每一个用户通过角色获得一组权限集合,权限系统的功能是验证用户申请的权限(集合)是否在这个集合当中,即申请的权限(集合)是否投影在用户拥有的权限集合,换句话说:只要某用户直接或者间接的属于某个Role那么它就具备这个Role的所有权限许可。


一个自主型访问控制方法的权限系统包括以下几个部分:角色、权限、访问控制表、


l         权限


描述一个权限可以通过以下几个要素说明:


类型(class):


名称(name):


动作(actions):


掩码(mask):


属性:


具体权限Example:


1、Test


类型(class):com.yangjs.secutiry. permissions. TestPermission


名称(name):如:test.* ,test.sub.* ,test.sub1.sub2


动作(actions): brower_detail ,post,repost,……


掩码(mask):0x1,0x2,0x4…..


属性: 无


.…………..


l         存取控制器(my--acl.xml)配置


存取控制项(ACE):角色到权限的映射集合,表示某个角色可以在某些资源上执行某些动作,它们之间通过role关联(继承),ACE之间产生包含关系。


存取控制列表(ACL):ACE的集合。


我们的存取控制器(ACL)是通过一个xml的配置文件说明,存取控制列表由多个存取控制项(ACE)来描述。使用方法(略)


2、细粒度权限设计


    细粒度授权需要上下文的支持,而且每个权限控制的上下问题都不一样,这由相关的业务逻辑决定,而且此类授权一般变化较快,应此需要将强的可维护性和扩展性,支持变化,但又不能够太复杂,否则缺乏可执行性。虽然此类权限个性化较强,我们仍然可以总结出很多共性:


1.       几乎所有的授权需要用户的角色和ID.


2.       特定的上下文几乎都同用户资源使用情况相关.


   我们将此类信息称为UserState 即:User角色以及资源使用情况和当前状态。大部分信息我们在用户登陆的时候已经。获得。授权贯穿Web层和Biz层,因此我们的登陆要独立于Web端。因此上下文我们可以用UserState结合其他来抽象。


   关于上下文的维护问题,我们不可能将UserState此类参数在Web层和Biz层来回传递,更加不能在需要授权的地方都加上一个这样的方法参数,这样不太现实。其次如果在授权的地方再从数据库中取一次这样虽然能够解决部分问题(不能解决userId的传递),这样效率太低,不能接受。


       解决方法就是将此类信息cache起来,用的时候再去取,由于此类信息具有非常高的并发性,对线程安全较高,因此我们决定将此类信息放入一个线程上下文的内存cache中。此外我们由于引入cache,就需要解决所有cache共有的维护性问题。


       Cache的生命周期:用户的一次请求,属于线程级,用户请求线程结束,Cache结束。


       Cache的更新:当上下文信息发生变化是需要及时更新Cache,这是一个不可避免的步骤。


        Cache丢失:发生在如系统down机,线程崩溃,内存溢出等等,对用户来说就是当前请求突然中断。


       当用户重新发送请求,我们的系统就需要重新验证用户,此时我们可以更新Cache解


       决丢失问题。


       Cache的清理:这个实现就是当用户请求结束,返回应答的时候清理,可以通过Filter实现,比较简单。


以上是相关的原理部分,我们看看系统地实现:


实现:线程上下文的cache


实现类:com.yangjs.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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值