RBAC角色权限模型设计

关于网站用户权限管理的设计模型。

我根据业内的一些标准和案例整理出一套RBAC用户权限设计模型文档。

希望对大家在系统设计时有帮助。

有其他见解请指教。

RBAC权限模型设计

 

在 RBAC社区的不断努力下,RBAC在 2004年 2月被美国国家标准委员会(ANSI)和  IT国际标准委员会(INCITS)接纳为ANSI INCITS 359-2004标准。       RBAC标准包括两个主要部分:RBAC参考模型和RBAC功能描述。

 

RBAC 是英文(Role-Based Access Control)的缩写,也就是基于角色的访问控制。RBAC 的定义比较晦涩,我就以比较生动的形式来阐述什么是 RBAC


 

ATM 机的一天

假设有一台 ATM(自动提款机)放在街边,我们来看看这个 ATM 度过的一天。

1.    早上,有一个家伙走到 ATM 面前,对着机器说:芝麻开门,芝麻开门,给我 100 块!。很显然 ATM 不会有任何动作。失望之余,这个家伙踢了 ATM 一脚走了。

2.    中午,一位漂亮的 Office lady 走到 ATM 机面前,放入她的信用卡,输入密码后,取出了 1200 块钱。当然,这些钱很快就会变成一件衣服或是化妆品。

3.    下班时分,银行的工作人员来到 ATM 机器面前,放入一张特制的磁卡,然后输入密码。从中查询到 ATM 机器内还有充足的现金,无需补充。所以他很高兴的开着车去下一台 ATM 机器所在地了。

现在我们要开发一台具有同样功能的 ATM 机,应该怎么做呢?

首先,我们的 ATM 机不能让人随便取钱,不然银行会破产的。接下来,ATM 机需要一个让人们放入磁卡并输入密码的设备。人们放入磁卡并输入密码后,ATM 机还要能够判断这张磁卡的卡号和密码是否有效,并且匹配。之后,ATM 机必须判断磁卡的卡号属于哪种类型,如果是信用卡,那么则显示查询账户余额和取款的界面。如果是特制的磁卡,则显示 ATM 机内的现金余额。


 

ATM RBAC

上面的例子显得有点荒诞,但是却是一个典型的基于角色的访问控制。

1.    对于没有磁卡或者输入了错误密码的用户,一律拒绝服务,也就是不允许进行任何其他操作;

2.    如果输入了正确的密码,必须判断用户输入哪一种类型,并提供相应的服务界面;

3.    如果用户尝试访问自己不能使用的服务,那么要明确告诉用户这是不可能的。

这个流程中,一共出现了两种角色:信用卡用户管理卡用户。而那些没有磁卡的用户,都属于没有角色一类。RBAC 要能够工作,至少需要两个数据:角色信息访问控制表

角色信息通常是指某个用户具有的角色,例如你持有一张信用卡,那么你就具有信用卡用户这个角色。如果你持有一张管理卡,那么你就具有管理卡用户这个角色。如果你既没有信用卡,又没有管理卡,那么你就没有上述两种角色。

有了角色信息,RBAC 系统还需要一个访问控制表。访问控制表(Access Control Table是一组数据,用于指出哪些角色可以使用哪个功能,哪些角色不能使用哪个功能。例如在 ATM 机中,具有信用卡用户角色,就可以使用查询账户余额和取款两项功能;而具有管理卡用户角色,就可以使用查询 ATM 机内现金余额的动能。

我们来模拟一次 ATM 机的操作:

1.    唐雷有一张信用卡,他放入 ATM 机并输入了正确的密码。这时,他被 ATM 机认为具有信用卡用户角色。

2.    根据上面的判断结果,ATM 机显示了一个操作界面,上面有查询账户余额和取款两项操作按钮。

3.    唐雷按下了查询账户余额按钮,ATM 机的查询账户余额功能被调用。

4.    在查询账户余额功能中,再次检查用户的角色信息,确定他可以使用这个功能。

5.    进行一系列操作,然后将唐雷信用卡账户上的余额数字显示到屏幕上。

6.    唐雷很郁闷他的信用卡又透支了,悻悻然取出卡走人了。这时 ATM 自动清除当前的角色信息,为下一次操作做好准备。

从上面可以看出,RBAC 充当了系统的一道安全屏障。所有的操作都需要进过 RBAC 验证过后才能使用。这样充分保证了系统的安全性。


 

RBAC 概念

FleaPHP RBAC 组件中,只有下列几项概念需要理解:

  • 用户:应用程序的使用者;
  • 角色:一个名字,可以为用户指定多个角色(0-n);
  • 访问控制表(ACT:一个数组,用来指明哪些功能可以被哪些角色访问或者限制访问。

除了上述三个概念,要想 RBAC 系统能够正常工作,还需要用户信息管理器、角色信息管理器和访问控制器三个部件。

  • 用户信息管理器:提供用户信息的存储、查询服务,以及为用户指定角色信息;
  • 角色信息管理器:提供角色信息的存储和查询服务
  • 访问控制器:根据角色信息和访问控制表进行验证

 

 

 

 

 

 

FleaPHP核心RBAC文件:

00001

00003 // FleaPHP Framework

00004 //

00005 // Copyright (c) 2005 - 2007 FleaPHP.org (www.fleaphp.org)

00006 //

00007 // 许可协议,请查看源代码中附带的 LICENSE.txt 文件,

00008 // 或者访问 http://www.fleaphp.org/ 获得详细信息。

00010

00030 class FLEA_Rbac

00031 {

00037     var $_sessionKey = 'RBAC_USERDATA';

00038

00044     var $_rolesKey = 'RBAC_ROLES';

00045

00051     function FLEA_Rbac()

00052     {

00053         $this->_sessionKey = FLEA::getAppInf('RBACSessionKey');

00054         if ($this->_sessionKey == 'RBAC_USERDATA') {

00055             trigger_error(_ET(0x0701005), E_USER_WARNING);

00056         }

00057     }

00058

00065     function setUser($userData, $rolesData = null)

00066     {

00067         if ($rolesData) {

00068             $userData[$this->_rolesKey] = $rolesData;

00069         }

00070         $_SESSION[$this->_sessionKey] = $userData;

00071     }

00072

00078     function getUser()

00079     {

00080         return isset($_SESSION[$this->_sessionKey]) ?

00081                 $_SESSION[$this->_sessionKey] :

00082                 null;

00083     }

00084

00088     function clearUser()

00089     {

00090         unset($_SESSION[$this->_sessionKey]);

00091     }

00092

00098     function getRoles()

00099     {

00100         $user = $this->getUser();

00101         return isset($user[$this->_rolesKey]) ?

00102                 $user[$this->_rolesKey] :

00103                 null;

00104     }

00105

00111     function getRolesArray()

00112     {

00113         $roles = $this->getRoles();

00114         if (is_array($roles)) { return $roles; }

00115         $tmp = array_map('trim', explode(',', $roles));

00116         return array_filter($tmp, 'trim');

00117     }

00118

00127     function check(& $roles, & $ACT)

00128     {

00129         $roles = array_map('strtoupper', $roles);

00130         if ($ACT['allow'] == RBAC_EVERYONE) {

00131             // 如果 allow 允许所有角色,deny 没有设置,则检查通过

00132             if ($ACT['deny'] == RBAC_NULL) { return true; }

00133             // 如果 deny RBAC_NO_ROLE,则只要用户具有角色就检查通过

00134             if ($ACT['deny'] == RBAC_NO_ROLE) {

00135                 if (empty($roles)) { return false; }

00136                 return true;

00137             }

00138             // 如果 deny RBAC_HAS_ROLE,则只有用户没有角色信息时才检查通过

00139             if ($ACT['deny'] == RBAC_HAS_ROLE) {

00140                 if (empty($roles)) { return true; }

00141                 return false;

00142             }

00143             // 如果 deny 也为 RBAC_EVERYONE,则表示 ACT 出现了冲突

00144             if ($ACT['deny'] == RBAC_EVERYONE) {

00145                 FLEA::loadClass('FLEA_Rbac_Exception_InvalidACT');

00146                 __THROW(new FLEA_Rbac_Exception_InvalidACT($ACT));

00147                 return false;

00148             }

00149

00150             // 只有 deny 中没有用户的角色信息,则检查通过

00151             foreach ($roles as $role) {

00152                 if (in_array($role, $ACT['deny'], true)) { return false; }

00153             }

00154             return true;

00155         }

00156

00157         do {

00158             // 如果 allow 要求用户具有角色,但用户没有角色时直接不通过检查

00159             if ($ACT['allow'] == RBAC_HAS_ROLE) {

00160                 if (!empty($roles)) { break; }

00161                 return false;

00162             }

00163

00164             // 如果 allow 要求用户没有角色,但用户有角色时直接不通过检查

00165             if ($ACT['allow'] == RBAC_NO_ROLE) {

00166                 if (empty($roles)) { break; }

00167                 return false;

00168             }

00169

00170             if ($ACT['allow'] != RBAC_NULL) {

00171                 // 如果 allow 要求用户具有特定角色,则进行检查

00172                 $passed = false;

00173                 foreach ($roles as $role) {

00174                     if (in_array($role, $ACT['allow'], true)) {

00175                         $passed = true;

00176                         break;

00177                     }

00178                 }

00179                 if (!$passed) { return false; }

00180             }

00181         } while (false);

00182

00183         // 如果 deny 没有设置,则检查通过

00184         if ($ACT['deny'] == RBAC_NULL) { return true; }

00185         // 如果 deny RBAC_NO_ROLE,则只要用户具有角色就检查通过

00186         if ($ACT['deny'] == RBAC_NO_ROLE) {

00187             if (empty($roles)) { return false; }

00188             return true;

00189         }

00190         // 如果 deny RBAC_HAS_ROLE,则只有用户没有角色信息时才检查通过

00191         if ($ACT['deny'] == RBAC_HAS_ROLE) {

00192             if (empty($roles)) { return true; }

00193             return false;

00194         }

00195         // 如果 deny RBAC_EVERYONE,则检查失败

00196         if ($ACT['deny'] == RBAC_EVERYONE) {

00197             return false;

00198         }

00199

00200         // 只有 deny 中没有用户的角色信息,则检查通过

00201         foreach ($roles as $role) {

00202             if (in_array($role, $ACT['deny'], true)) { return false; }

00203         }

00204         return true;

00205     }

00206

00214     function prepareACT($ACT)

00215     {

00216         $ret = array();

00217         $arr = array('allow', 'deny');

00218         foreach ($arr as $key) {

00219             do {

00220                 if (!isset($ACT[$key])) {

00221                     $value = RBAC_NULL;

00222                     break;

00223                 }

00224

00225                 if ($ACT[$key] == RBAC_EVERYONE || $ACT[$key] == RBAC_HAS_ROLE

00226                     || $ACT[$key] == RBAC_NO_ROLE || $ACT[$key] == RBAC_NULL) {

00227                     $value = $ACT[$key];

00228                     break;

00229                 }

00230

00231                 $value = explode(',', strtoupper($ACT[$key]));

00232                 $value = array_filter(array_map('trim', $value), 'trim');

00233                 if (empty($value)) { $value = RBAC_NULL; }

00234             } while (false);

00235             $ret[$key] = $value;

00236         }

00237

00238         return $ret;

00239     }

00240 }

 

 

 

 

 

RBAC角色权限设置文件

array(

    'allow' => '允许访问该控制器的角色名',

    'deny' => '禁止访问该控制器的角色名',

 

    'actions' => array(

        '动作名' => array(

            'allow' => '允许访问该动作的角色名',

            'deny' => '禁止访问该动作的角色名',

        ),

        // .... 更多动作

    ),

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

基于RBAC模型的通用权限管理系统的设计

(数据模型)的扩展

 

1 RBAC模型
      
访问控制是针对越权使用资源的防御措施。基本目标是为了限制访问主体(用户、进程、服务等)对访问客体(文件、系统等)的访问权限,从而使计算机系统在合法范围内使用;决定用户能做什么,也决定代表一定用户利益的程序能做什么[1]
        
企业环境中的访问控制策略一般有三种:自主型访问控制方法、强制型访问控制方法和基于角色的访问控制方法(RBAC)。其中,自主式太弱,强制式太强,二者工作量大,不便于管理[1]。基于角色的访问控制方法是目前公认的解决大型企业的统一资源访问控制的有效方法。其显著的两大特征是:1.减小授权管理的复杂性,降低管理开销;2.灵活地支持企业的安全策略,并对企业的变化有很大的伸缩性。
       NIST
The National Institute of Standards and Technology,美国国家标准与技术研究院)标准RBAC模型由4个部件模型组成,这4个部件模型分别是基本模型RBAC0Core RBAC)、角色分级模型RBAC1Hierarchal RBAC)、角色限制模型RBAC2Constraint RBAC)和统一模型RBAC3Combines RBAC[1]RBAC0模型如图1所示。
         a. RBAC0
定义了能构成一个RBAC控制系统的最小的元素集合。在RBAC之中,包含用户users(USERS)、角色roles(ROLES)、目标objects(OBS)、操作operations(OPS)、许可权permissions(PRMS)五个基本数据元素,权限被赋予角色,而不是用户,当一个角色被指定给一个用户时,此用户就拥有了该角色所包含的权限。会话sessions是用户与激活的角色集合之间的映射。RBAC0与传统访问控制的差别在于增加一层间接性带来了灵活性,RBAC1RBAC2RBAC3都是先后在RBAC0上的扩展。
         b. RBAC1
引入角色间的继承关系,角色间的继承关系可分为一般继承关系和受限继承关系。一般继承关系仅要求角色继承关系是一个绝对偏序关系,允许角色间的多继承。而受限继承关系则进一步要求角色继承关系是一个树结构。
        c. RBAC2
模型中添加了责任分离关系。RBAC2的约束规定了权限被赋予角色时,或角色被赋予用户时,以及当用户在某一时刻激活一个角色时所应遵循的强制性规则。责任分离包括静态责任分离和动态责任分离。约束与用户-角色-权限关系一起决定了RBAC2模型中用户的访问许可。
        d. RBAC3
包含了RBAC1RBAC2,既提供了角色间的继承关系,又提供了责任分离关系。

 2核心对象模型设计

      根据RBAC模型的权限设计思想,建立权限管理系统的核心对象模型.对象模型中包含的基本元素主要有:用户(Users)、用户组(Group)、角色(Role)、目标(Objects)、访问模式(Access Mode)、操作(Operator)。主要的关系有:分配角色权限PAPermission Assignment)、分配用户角色UAUsers Assignmen描述如下:

       a .控制对象:是系统所要保护的资源(Resource),可以被访问的对象。资源的定义需要注意以下两个问题:
       1.
资源具有层次关系和包含关系。例如,网页是资源,网页上的按钮、文本框等对象也是资源,是网页节点的子节点,如可以访问按钮,则必须能够访问页面。
       2.
这里提及的资源概念是指资源的类别(Resource Class),不是某个特定资源的实例(Resource Instance)。资源的类别和资源的实例的区分,以及资源的粒度的细分,有利于确定权限管理系统和应用系统之间的管理边界,权限管理系统需要对于资源的类别进行权限管理,而应用系统需要对特定资源的实例进行权限管理。两者的区分主要是基于以下两点考虑:
       
一方面,资源实例的权限常具有资源的相关性。即根据资源实例和访问资源的主体之间的关联关系,才可能进行资源的实例权限判断。 例如,在管理信息系统中,需要按照营业区域划分不同部门的客户,A区和B区都具有修改客户资料这一受控的资源,这里客户档案资料是属于资源的类别的范畴。如果规定A区只能修改A区管理的客户资料,就必须要区分出资料的归属,这里的资源是属于资源实例的范畴。客户档案(资源)本身应该有其使用者的信息(客户资料可能就含有营业区域这一属性),才能区分特定资源的实例操作,可以修改属于自己管辖的信息内容。
       
另一方面,资源的实例权限常具有相当大的业务逻辑相关性。对不同的业务逻辑,常常意味着完全不同的权限判定原则和策略。
        b.
权限:对受保护的资源操作的访问许可(Access Permission),是绑定在特定的资源实例上的。对应地,访问策略(Access Strategy)和资源类别相关,不同的资源类别可能采用不同的访问模式(Access Mode)。例如,页面具有能打开、不能打开的访问模式,按钮具有可用、不可用的访问模式,文本编辑框具有可编辑、不可编辑的访问模式。同一资源的访问策略可能存在排斥和包含关系。例如,某个数据集的可修改访问模式就包含了可查询访问模式。
        c.
用户:是权限的拥有者或主体。用户和权限实现分离,通过授权管理进行绑定。
        d.
用户组:一组用户的集合。在业务逻辑的判断中,可以实现基于个人身份或组的身份进行判断。系统弱化了用户组的概念,主要实现用户(个人的身份)的方式。 
        e.
角色:权限分配的单位与载体。角色通过继承关系支持分级的权限实现。例如,科长角色同时具有科长角色、科内不同业务人员角色。
        f.
操作:完成资源的类别和访问策略之间的绑定。
        g.
分配角色权限PA:实现操作和角色之间的关联关系映射。
        h.
分配用户角色UA:实现用户和角色之间的关联关系映射。

 该对象模型最终将访问控制模型转化为访问矩阵形式。访问矩阵中的行对应于用户,列对应于操作,每个矩阵元素规定了相应的角色,对应于相应的目标被准予的访问许可、实施行为。按访问矩阵中的行看,是访问能力表CL(Access Capabilities)的内容;按访问矩阵中的列看,是访问控制表ACLAccess Control Lists)的内容。
数据模型图如下:

RBAC角色权限模型设计_第1张图片

 希望各位多提意见 ,再完善

 

 

你可能感兴趣的:(PHP)