首页  ·  知识 ·  软件项目
权限设计原理
红燕  CIOZJ  综合  编辑:红燕   图片来源:网络
权限往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断“Who对What(Which)进行How的操作”的逻辑表达式是否为真。针对不同的应用,需要根据项目的实际情况和具体架构,在维护

一、           权限设计概要

1.1前言

权限往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断“Who对What(Which)进行How的操作”的逻辑表达式是否为真。针对不同的应用,需要根据项目的实际情况和具体架构,在维护性、灵活性、完整性等N多个方案之间比较权衡,

1.2目标

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

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

扩展,采用可继承的方式解决了权限在扩展上的困难。引进Group概念在支持权限以组方式定义的同时有效避免了权限的重复定义。

1.3现状

对于在企业环境中的访问控制方法,一般有三种:

1.自主型访问控制方法(DAC/授权Authorization)。目前在我国的大多数的信息系统中的访问控制模块中基本是借助于自主型访问控制方法中的访问控制列表(ACLs)。

 

2.强制型访问控制方法(多级安全/Multilevel Security)。用于多层次安全级别的军事应用。

 

3.基于角色的访问控制方法(RBAC-Role-Based Access Control)。是目前公认的解决大型企业的统一资源访问控制的有效方法。其显著的两大特征是:

1.减小授权管理的复杂性,降低管理开销。

2.灵活地支持企业的安全策略,并对企业的变化有很大的伸缩性。

二、           权限设计原则

2.1原则简述

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

需要再次强调的是,这里表述的权限系统仅是一个"不完全"的权限系统,即,它不提供所有关于权限的问题的解决方法。它提供一个基础,并解决那些具有"共性"的(或者说粗粒度的)部分。在这个基础之上,根据"业务逻辑"的独特权限需求,编码实现剩余部分(或者说细粒度的)部分,才算完整。回到权限的问题公式,通用的设计仅解决了Who+What+How 的问题,其他的权限问题留给业务逻辑解决。

 

2.2相关名词解释

粗粒度:表示类别级,即仅考虑对象的类别(the type of object),不考虑对象的某个特定实例。

比如,用户管理中,创建、删除,对所有的用户都一视同仁,并不区分操作的具体对象实例。

细粒度:表示实例级或数据级,即需要考虑具体对象的实例(the instance of object)或对象的属性,当然,细粒度是在考虑粗粒度的对象类别之后才再考虑特定实例。

比如,合同管理中,列表、删除,需要区分该合同实例是否为当前用户所创建。

 

Who权限的拥用者或主体(Principal、User、Group、Role、Actor等等)

What权限针对的对象或资源(Resource、Class)。

How具体的权限(Privilege, 正向授权与负向授权)。

 

User与 Role 相关,用户仅仅是纯粹的用户,权限是被分离出去了的。User是不能与 Privilege 直接相关的,User 要拥有对某种资源的权限,必须通过Role去关联。(注:在如blog中的细粒度权限的解决,控制应该在底层解决。Resource在实例化的时候,必需指定Owner和GroupPrivilege。)解决 Who 的问题。

 

Role是角色,拥有一定数量的权限。是粗粒度和细粒度(业务逻辑)的接口,一个基于粗粒度控制的权限框架软件,对外的接口应该是Role,具体业务实现可以直接继承或拓展丰富Role的内容,Role不是如同User或Group的具体实体,它是接口概念,抽象的通称。

有关role和group的定义有需要补充的地方:根据模型的不同(如RBAC和GBAC等等)role和group的概念是有很容易混淆的。下面的对Group的定义实际上也是有针对性的(似乎是基于RGAC模型的定义)。把权限分配给组还是分配给角色应该根据实际情况和权限模型具体分析。在rbac中,权限只赋予role,通过role的分层继承概念和强制性约束条件从而达成了权限的控制。但对于细粒度的控制(如不同部门的相同角色,他们的操作相同,但资源客体不同)上实现就比较复杂。我大致了解了一下,gbac出发点似乎更注重将相同权限进行抽象集合(相同的权限规定为一个组),并通过继承等概念赋予不同用户的操作授权。

 

举个简单的例子:一个公司中如果只一个部门,从这个部门中再划分不同的职务。这样的话role和group所起的作用是重合的,我们只需引入其一即可;但如果有了多个部门,我们可以同时引入角色和组(一个部门一个组),组里又有相同的role(此时role拥有相同的权利,但部门不同,职能范围不同)。这样一来,将权限分配给组还是分配和role、是对role进行约束还是对组进行约束是需要我们根据具体情况进行分析和选型的。这里给出的概念只是网上比较经典的一些论述,整理出来有助于大家学习。所以在后面介绍RBAC时给出的概念可能和现在给出的概念有所区别。

 

 

 

Group用户组,权限分配的单位与载体。权限不考虑分配给特定的用户。组可以包括组(以实现权限的继承)。组可以包含用户,组内用户继承组的权限。Group要实现继承。即在创建时必须要指定该Group的Parent是什么Group。

在粗粒度控制上,可以认为,只要某用户直接或者间接的属于某个Group那么它就具备这个Group的所有操作许可。

细粒度控制上,在业务逻辑的判断中,User仅应关注其直接属于的Group,用来判断是否"同组" 。

Group是可继承的,对于一个分级的权限实现,某个Group通过"继承"就已经直接获得了其父Group所拥有的所有"权限集合",对这个Group而言,需要与权限建立直接关联的,仅是它比起其父Group需要"扩展"的那部分权限。子组继承父组的所有权限,规则来得更简单,同时意味着管理更容易。

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

Resource[注:应等同于object]就是系统的资源,比如部门新闻,文档等各种可以被提供给用户访问的对象。资源可以反向包含自身,即树状结构,每一个资源节点可以与若干指定权限类别相关可定义是否将其权限应用于子节点。

Privilege[注:应等同于permission]是Resource Related的权限。就是指,这个权限是绑定在特定的资源实例上的。比如说部门新闻的发布权限,叫做"部门新闻发布权限"。这就表明,该Privilege是一个发布权限,而且是针对部门新闻这种资源的一种发布权限。Privilege是由Creator在做开发时就确定的。权限,包括系统定义权限和用户自定义权限用户自定义。权限之间可以指定排斥和包含关系(如:读取,修改,管理三个权限,管理 权限 包含 前两种权限)。Privilege 如"删除" 是一个抽象的名词,当它不与任何具体的 Object 或 Resource 绑定在一起时是没有任何意义的。拿新闻发布来说,发布是一种权限,但是只说发布它是毫无意义的,只有当发布与新闻结合在一起才会产生真正的 Privilege。

Operator操作。表明对What的How 操作。Operator的定义包括了Resource Type和Method概念。即,What和How的概念。之所以将What和How绑定在一起作为一个Operator概念而不是分开建模再建立关联,这是因为很多的How对于某What才有意义。比如,发布操作对新闻对象才有意义,对用户对象则没有意义。How本身的意义也有所不同,具体来说,对于每一个What可以定义N种操作。比如,对于合同这类对象,可以定义创建操作、提交操作、检查冲突操作等。可以认为,How概念对应于每一个商业方法。其中,与具体用户身份相关的操作既可以定义在操作的业务逻辑之中,也可以定义在操作级别。比如,创建者的浏览视图与普通用户的浏览视图要求内容不同。既可以在外部定义两个操作方法,也可以在一个操作方法的内部根据具体逻辑进行处理。具体应用哪一种方式应依据实际情况进行处理。这样的架构,应能在易于理解和管理的情况下,满足绝大部分粗粒度权限控制的功能需要。但是除了粗粒度权限,系统中必然还会包括无数对具体Instance的细粒度权限。这些问题,被留给业务逻辑来解决,这样的考虑基于以下两点:

一方面,细粒度的权限判断必须要在资源上建模权限分配的支持信息才可能得以实现。比如,如果要求创建者和普通用户看到不同的信息内容,那么,资源本身应该有其创建者的信息。

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

所以细粒度控制应该在底层解决,Resource在实例化的时候,必需指定Owner和GroupPrivilege。在对Resource进行操作时也必然会确定约束类型:究竟是OwnerOK还是GroupOK还是AllOK。Group应和Role严格分离,User和Group是多对多的关系,Group只用于对用户分类,不包含任何Role的意义;Role只授予User,而不是Group。如果用户需要还没有的多种Privilege的组合,必须新增Role。Privilege必须能够访问Resource,同时带User参数,这样权限控制就完备了。

 

Domain为了授权更灵活,可以将Where或者Scope抽象出来,称之为Domain,真正的授权是在Domain的范围内进行,具体的Resource将分属于不同的Domain。比如:一个新闻机构有国内与国外两大分支,两大分支内又都有不同的资源(体育类、生活类、时事政治类)。假如所有国内新闻的权限规则都是一样的,所有国外新闻的权限规则也相同。则可以建立两个域,分别授权,然后只要将各类新闻与不同的域关联,受域上的权限控制,从而使之简化。

 

正向授权与负向授权:正向授权在开始时假定主体没有任何权限,然后根据需要授予权限,适合要求严格的系统。负向授权在开始时假定主体有所有权限,然后将某些特殊权限收回。

2.3权限设计思想

权限系统的核心由以下三部分构成:

²  创造权限 - Creator创造,

²  分配权限 - Administrator 分配,

²  使用权限 - User

 

1. Creator 创造 Privilege, Creator 在设计和实现系统时会划分,一个子系统或称为模块,应该有哪些权限。这里完成的是 Privilege 与 Resource 的对象声明,并没有真正将 Privilege 与具体Resource 实例联系在一起,使之形成Operator。

 

2. Administrator 指定 Privilege 与 Resource Instance 的关联。在这一步, 权限真正与资源实例联系到了一起, 产生了Operator(Privilege Instance)。Administrator利用Operator这个基本元素,来创造他理想中的权限模型。如,创建角色,创建用户组,给用户组分配用户,将用户组与角色关联等等...这些操作都是由 Administrator 来完成的。

 

3. User 使用 Administrator 分配给的权限去使用各个子系统。Administrator 是用户,在他的心目中有一个比较适合他管理和维护的权限模型。于是,程序员只要回答一个问题,就是什么权限可以访问什么资源,也就是前面说的 Operator。程序员提供 Operator 就意味着给系统穿上了盔甲。Administrator 就可以按照他的意愿来建立他所希望的权限框架可以自行增加,删除,管理Resource和Privilege之间关系。可以自行设定用户User和角色Role的对应关系。(如果将 Creator看作是 Basic 的发明者, Administrator 就是 Basic 的使用者,他可以做一些脚本式的编程) Operator是这个系统中最关键的部分,它是一个纽带,一个系在Programmer,Administrator,User之间的纽带。

2.4权限设计示例

A、建立角色功能并做分配

1.如果现在要做一个员工管理的模块(即Resources),这个模块有三个功能,分别是:增加,修改,删除。给这三个功能各自分配一个ID,这个ID叫做功能代号:

Emp_addEmp,Emp_deleteEmp,Emp_updateEmp

2.建立一个角色(Role),把上面的功能代码加到这个角色拥有的权限中,并保存到数据库中。角色包括系统管理员,测试人员等。

3.建立一个员工的账号,并把一种或几种角色赋给这个员工。比如说这个员工既可以是公司管理人员,也可以是测试人员等。这样他登录到系统中将会只看到他拥有权限的那些模块。

 

B、把身份信息加到Session中

登录时,先到数据库中查找是否存在这个员工,如果存在,再根据员工的sn查找员工的权限信息,把员工所有的权限信息都入到一个Hashmap中,比如就把上面的Emp_addEmp等放到这个Hashmap中。然后把Hashmap保存在一个UserInfoBean中。最后把这个UserInfoBean放到Session中,这样在整个程序的运行过程中,系统随时都可以取得这个用户的身份信息。

C、根据用户的权限做出不同的显示

可以对比当前员工的权限和给这个菜单分配的"功能ID"判断当前用户是否有打开这个菜单的权限。例如:如果保存员工权限的Hashmap中没有这三个ID的任何一个,那这个菜单就不会显示,如果员工的Hashmap中有任何一个ID,那这个菜单都会显示。

对于一个新闻系统(Resouce),假设它有这样的功能(Privilege):查看,发布,删除,修改;假设对于删除,有"新闻系统管理者只能删除一月前发布的,而超级管理员可删除所有的这样的限制,这属于业务逻辑(Business logic),而不属于用户权限范围。也就是说权限负责有没有删除的Permission,至于能删除哪些内容应该根据UserRole or UserGroup来决定(当然给UserRole or UserGroup分配权限时就应该包含上面两条业务逻辑)。

一个用户可以拥有多种角色,但同一时刻用户只能用一种角色进入系统(???)。角色的划分方法可以根据实际情况划分,按部门或机构进行划分的,至于角色拥有多少权限,这就看系统管理员赋给他多少的权限了。用户—角色—权限的关键是角色。用户登录时是以用户和角色两种属性进行登录的(因为一个用户可以拥有多种角色,但同一时刻只能扮演一种角色),根据角色得到用户的权限,登录后进行初始化。这其中的技巧是同一时刻某一用户只能用一种角色进行登录。

针对不同的"角色"动态的建立不同的组,每个项目建立一个单独的Group,对于新的项目,建立新的 Group 即可。在权限判断部分,应在商业方法上予以控制。比如:不同用户的"操作能力"是不同的(粗粒度的控制应能满足要求),不同用户的"可视区域"是不同的(体现在对被操作的对象的权限数据,是否允许当前用户访问,这需要对业务数据建模的时候考虑权限控制需要)。

Croe RBAC定义了5个基本元素集合(USERS、ROLES、OBS、OPS、PRMS),RBAC模型的本质其实就是基于这几个基本集合的一系列关系(如图)。包括:角色授权关系(PA)、用户的角色授权关系(UA)和角色的层次关系(RH)等;一些函数,包括:会话到用户的映射()、会话到角色集合的映射()等;以及一些相关约束。

 

 

用户(Users):一个用户被定义成一个人。虽然它的概念可以扩展成一个机器、网络、以及智能代理等,但我们为了简单起见,在这个文档中我们将用户定义成一个人的概念。

角色(Role):在一个组织机构的关系中,Role表示一个工作职责。如果将用户指派到角色上,则Role暗含关联权限和职责的语义。

权限(Permission):一个许可,是对一个或多个Object执行operation的许可。(资源客体objects(OBS))、操作(operations(OPS))

会话(Session):会话在RBAC标准草案中似乎没有给出具体定义,它跟web应用中session的概念有些不同。根据标准发布的内容可以看出session在rbac中是一个关系映射的概念。具体来说是一个user和一(多)个role之间关系的映射;

    在一个RBAC模型的系统中,每个用户进入系统得到自己的控制时,就得到了一个session。每个session是动态产生的,从属于一个用户。只要静态定义过这些角色与该用户的关系,会话根据用户的要求负责将它所代表的用户映射到多个角色中去。一个session可能激活的角色是用户的全部角色的一个子集,对于用户而言,在一个session内可获得全部被激活的角色所代表的访问许可权。角色和会话的设置带来的好处是容易实施最小特权原则(Least-Privilege Principle)。所谓最小特权原则是将超级用户的所有特权分解成一组细粒度的特权子集,定义成不同的“角色”,分别赋予不同的用户,每个用户仅拥有完成其工作所必须的最小特权,避免了超级用户的误操作或其身份被假冒后而产生的安全隐患。

一个session只能关联一个user,一个user可以关联多个sessions;上面的图例中有两个函数:user_sessions给出了和用户关联的session集合;session_roles给出了roles activated(激活的角色)。

session由用户控制,允许动态激活/取消角色,实现最小特权。应避免同时激活所有角色;session和user分离可以解决同一用户多账号带来的问题,如审计、计账等

 

实现核心RBAC必须具备的功能

1、 管理方面的功能:增加及删除使用者、增加及删除角色、分配角色给使用者及移除原先分配给使用者的角色、分配权利给角色及移除原先分配给角色的权利

2、 系统支持方面的功能:产生或删除一个会话期、在一个会话期加入或删除角色,既能在一个会话期启动或停止部分角色、检查一个会话期是否具有某个权利。

3、 核查(Review)功能:查询所有拥有某一角色的使用者、查询一个使用者所拥有的全部角色。

4、 增强型核查功能:查询一个角色所有的权利、查询一个使用者所拥有的权利、查询一个会话期所启用的角色、查询一个会话期所具有的权利、查询一个角色对某一个物件所能行使的操作、查询一个使用者对某一个物件所能行使的操作

 

B模型1Hierarchical RBAC

    Hierarchical RBAC在core RBAC的基础上引入了角色继承的概念。如图所示:

 

Hierarchical是反映一个组织结构层次的授权和责任的自然方式,它定义了角色的继承关系。如:Role r1 “继承” Role r2,则角色r2的权限同样是r1的权限。相比较core RBAC,角色分层带来的好处就是解决了重复授权的问题。例如:在没有引入角色分层概念时,经理和高级经理的权限可能有80%都是重合的。这样一来管理员具体实施时对角色授权的重复操作度就很高。而且随着组织结构层次复杂度的提高,这种授权操作的复杂度成线性增加;在引入了role hierarchy后高级经理自动获取经理的所有权限,然后管理员在分配其特有的权限即可。见过类似的公式推导,以一个全国性跨地区的公司,角色分层的实现和不实现相比其赋权的复杂度降低了约十倍。

 

C模型2Static Separation of Duty Relations

 

SSD定义了一个用户角色分配的约束关系,一个用户不可能同时分配SSD中的两个角色。它的作用就是避免了角色的冲突。举个简单的例子:在一个公司,一个员工不应该既是会计又是出纳(注意:一个财务经理,如果她既继承了会计的角色又继承了财务的角色。这种特殊的情况没有很好的解决办法。应尽力避免)。在User Assignment中引入SSD,这样在系统初始化的时候,当角色授权给用户时来判断是否将冲突的角色给了一个用户。在Static Separation of Duty Relations模型中冲突的角色用一个二元关系定义,任何一个用户只能拥有其中的一个角色。

 

动态分离的概念是指两个或多个冲突的角色可以赋给一个用户。它的特点不是在系统初始化时将责任进行分离,而是在一个用户会话过程进行约束。虽然用户可以同时启用这两种角色,但同一会话期只能选择其一。

3.1 一个RBAC模型的实现

一、           ACL(Access Control List)介绍

4.1 ACL(Access Control List)概述

       不好意思,查了N久也没看到ACL名称的历史和起源。目前大家能看到ACL使用最多的地方基本都是在网络安全配置和UNIX系统安全配置中。简单的总结一下:所谓的ACL就是指访问控制列表,是存储在计算机中的一张表。它记录了用户和设备可以访问哪些现有资源(文件目录、单个文件、数据等等),是用来保证系统安全性的一种手段。

4.2 ACL在web应用中描述

1. Java acl开始第一步是建立一个主体 Principal,其中SecurityOwner是主体的拥有者:

private static final Principal _securityOwner = new PrincipalImpl("SecurityOwner");

补上:主体的定义。主体表示一个实体,如单独用户或一个用户组

 

2. 当用户login进来时,他带有两个基本数据:访问密码和他要访问的对象ApplicationName。首先验证用户名和密码,然后从数据库中取出其权限数据,建立Permission,这里使用Feature继承了Permission,在Feature中定义了有关权限的细节数据(如读 写 删)。

// 取出用户和被访问对象之间的权限关系,这种权限关系可能不只一个,也就是说,用户

//可能对被访问对象拥有读 写 删等多个权限,将其打包在Hasbtable中。

Hashtable features = loadFeaturesForUser(sApplicationName, sUserID);

 

3. 创建一个用户对象

User user = new UserImpl(sUserID, new Hashtable() );

 

4. 为这个用户创建一个活动的acl entry

addAclEntry( user, features);

其中最关键的是第四步addAclEntry,我们看看其如何实现的:

// 为这个用户创建一个新的Acl entry

AclEntry newAclEntry = new AclEntryImpl( user);

//遍历Hashtable features,将其中多种权限加入:

....

feature = (Feature) hFeatures.get(keyName);

newAclEntry.addPermission( feature );

....

最后也要加入主体拥有者SecurityOwner,这样一个安全体系就已经建立完成。当你在系统中要检验某个用户使用拥有某个权限,如读的权利时,只要

acl.checkPermission(user, feature )就可以,acl是ACL的一个实例,这样权限检查就交给

java.security.acl.ACL 去处理了。

 

 

 

 

 

 

当一个用户login后,我们就要在内存中为其建立相应的授权访问机制,使用java.security.acl可以很方便的建立这样一个安全系统。

 

 

An—introduction-to-rbac:7页、Grbc中权限和group相连。实际上rbac也借鉴了gbac的概念,group和user都和组织机构有关,但不是组织机构。二者在概念上是不同的

 

 

我个人理解group组一般按企业的组织结构来,分部门。role角色一般按职能来,它是对组的细化和补充,role分为全局role和局部

 

roleActor作为一个通用的接口与Role通讯。Role作为一个用户与权限的代理层,解耦了权限和用户的关系,所有的授权应该给予Role而不是直接给User或Group。

 

PrivilegeManager(名字不好听)就是用来进行R-P之间的关系操作的。例如getRoleByPrivilege()之类的。

SecurityManager作为系统对外的接口,接受Actor,Resource,Operation作为参数,

并判断Actor中的Role是否有操作Privilege(Resource,Operation)的权限。

 

 

(个人理解:这两个函数的作用是:当一个用户做某些操作时,user_sessions给出了和这个用户关联的sessions,而session_roles又给出和用户关联的可用roles,这样就完成了用户和角色的关联――暂时标注)

本文作者:红燕 来源:CIOZJ
CIO之家 www.ciozj.com 微信公众号:imciow
    >>频道首页  >>网站首页   纠错  >>投诉
版权声明:CIO之家尊重行业规范,每篇文章都注明有明确的作者和来源;CIO之家的原创文章,请转载时务必注明文章作者和来源;
延伸阅读