RBAC php

本文来给大家介绍一下“基于角色的访问控制 ”,

说到权限,大家就很头疼,怎么样能灵活把控好一个用户的权限,

有些同学会在用户表中加字段或者是在角色表中加相应的权限字段,

这样会有一个问题,做起权限来会感觉特别的蹩脚,而且很不灵活,每增加一种权限就要在数据库中增加一个字段,很不利于项目的迭代开发

那么我们就需要一种非常灵活的设计模式RBAC,即基于角色的访问控制;


我来给大家说下这种设计思想:


首先,我们的需求是判断某一个用户对当前操作的控制器或控制器的方法是否有权限访问,

如果多个用户同时拥有同样的权限,那我们就需要给这些用户指定同一个用户角色,然后只需要通过角色来对操作的访问进行权限控制,


那我们表结构需要这样来设计,这个很重要,如下:


第一张数据表(用户表):



字段名称 字段说明
id 用户ID(主键自增)
username 用户名
password 用户密码




第二张数据表(角色表):

字段名称 字段说明
id 用户角色ID(主键自增)
name 用户角色名称
 



第三张数据表(节点表):
字段名称 字段说明
id 操作节点ID(主键自增)
name 操作节点的名称
zh_name 节点的中文说明



我们使用第三范式来设计关联表,这样做的好处是,避免数据冗余,并且对于一对多,多对一的关系都可以清晰的记录,条理清晰


第四张数据表(节点对应角色表):
字段名称 字段说明
role_id 用户角色ID(外键,关联角色表中的主键ID)
note_id 操作节点ID(外键,关联节点表中的主键ID)





第五张数据表(用户对应角色表):
字段名称 字段说明
role_id 用户角色ID(外键,关联角色表中的主键ID)
user_id 用户ID(外键,关联用户表中的主键ID)




通过这五张表就可以对权限进行访问控制,它的具体操作步骤如下:

用户输入用户名密码登录,


通过用户表判断,如果输入的用户名密码不合法,跳回重新登录


如果合法,在用户表中返回用户的ID号,


通过此用户ID号,到用户与角色的关联表中查询出用户的角色ID号,


拿到角色ID号,通过此ID号到角色与节点的关联表中查询出此角色拥有的节点访问权限,


将此权限节点全部存入SESSION中,当用户访问某一个模块的时候,


例如:http://www.lampbroher.net/index.php/stu/index


我们用session中的权限与$_GET['m']与$_GET['a']去对比,


如果$_GET['m']或者$_GET['a']在SESSION中不存在,说明该用户没有此权限,作出处理即可。


参考代码:


RBAC类文件:

  1. <?php
  2.     /*+---------------------------------------------------------------------------------------+
  3.       | RBAC权限控制类
  4.       +-----------------------------------------------------------------------------------------+
  5.       | 版权所有 lamp兄弟连                        
  6.       +-----------------------------------------------------------------------------------------+
  7.       | 作者: 李捷 (lijie@li-jie.me)                            
  8.       | 最后修改时间: 2012-05-06 18:30                                          
  9.       +-----------------------------------------------------------------------------------------+
  10.     */
  11.     class  Rbac{
  12.         private $node_tablename;                    //定义私有属性节点表名称
  13.         private $group_auth_tablename;        //定义私有属性组权限表名称
  14.         private $group_tablename;                //定义私有属性用户组表名称
  15.         private $group_user_tablename;        //定义私有属性用户归属组表名称
  16.         private $user_tablename;                    //定义私有属性用户表名称
  17.         
  18.         /*
  19.             构造方法
  20.             @param1 string 节点表名称
  21.             @param2 string 用户权限表名称
  22.             @param3 string 用户组表名称
  23.             @param4 string 用户归属组表名称
  24.             @param5 string 用户表名称
  25.         */
  26.         public function __construct($node_tablename='node',$group_auth_tablename='group_auth',$group_tablename='group',$group_user_tablename='group_member',$user_tablename='member'){
  27.             $this->node_tablename = $node_tablename;                            //获取节点表名称
  28.             $this->group_auth_tablename = $group_auth_tablename;        //获取用户权限表名称
  29.             $this->group_tablename = $group_tablename;                        //获取用户组表名称
  30.             $this->group_user_tablename = $group_user_tablename;        //获取用户归属组表名称
  31.             $this->user_tablename = $user_tablename;                                //获取用户表名称
  32.         }
  33.         
  34.         /*
  35.             设置节点方法
  36.             @param1 string 节点名称
  37.             @param2 string 节点父ID
  38.             @param2 string 节点中文说明
  39.             @return int 插入节点记录成功以后的ID
  40.         */
  41.         public function set_node($name,$pid,$zh_name=''){
  42.             if(!empty($name) && !empty($pid)){
  43.                 $node = D($this->node_tablename)->insert(array("name"=>$name,"pid"=>$pid,"zh_name"=>$zh_name));
  44.             }
  45.             return $node;
  46.         }
  47.         
  48.         /*
  49.             设置权限方法
  50.             @param1 int 组ID
  51.             @param2 int 节点ID
  52.             @return int 插入权限记录成功以后的ID
  53.         */
  54.         public function set_auth($gid,$nid){
  55.             if(!empty($gid) && !empty($nid)){
  56.                 $auth = D($this->group_auth_tablename)->insert(array("gid"=>$gid,"nid"=>$nid));
  57.             }
  58.             return $auth;
  59.         }
  60.         
  61.         /*
  62.             获取节点方法
  63.             @param1 int 节点ID
  64.             @return array 获取到节点表的相关信息
  65.         */
  66.         public function get_node($id){
  67.             if(!empty($id)){
  68.                 $data = D($this->node_tablename)->field("id,name,pid")->where(array('id'=>$id))->find();
  69.                 return $data;
  70.             }else{
  71.                 return false;
  72.             }
  73.         }
  74.         
  75.         /*
  76.             获取组权限方法
  77.             @param1 int 用户组ID
  78.             @return array 获取到组权限表的相关信息
  79.         */
  80.         
  81.         public function get_auth($gid){
  82.             if(!empty($gid)){
  83.                 $data = D($this->group_auth_tablename)->field("nid")->where(array('gid'=>$gid))->select();
  84.                 return $data;
  85.             }else{
  86.                 return false;
  87.             }
  88.         }
  89.         
  90.         /*
  91.             获取用户组方法
  92.             @param1 int 用户ID
  93.             @return array 获取该用户所对应的用户组id
  94.         */
  95.         
  96.         public function get_group($uid){
  97.             if(!empty($uid)){
  98.                 $data = D($this->group_user_tablename)->field("gid")->where(array('uid'=>$uid))->select();
  99.                 return $data;
  100.             }else{
  101.                 return false;
  102.             }
  103.         }
  104.         
  105.         /*
  106.             获取节点的子节点方法
  107.             @param1 int 节点ID
  108.             @return array 获取该节点所对应的全部子节点
  109.         */
  110.         
  111.         public function get_cnode($nid){
  112.             if(!empty($nid)){
  113.                 $cnode = D($this->node_tablename)->field("name")->where(array('pid'=>$nid))->select();
  114.                 return $cnode;
  115.             }else{
  116.                 return false;
  117.             }
  118.         }
  119.         
  120.         /*
  121.             获取权限方法
  122.             @param1 int 用户ID
  123.             @return array 得到权限列表
  124.         */
  125.         
  126.         public function get_access($uid){
  127.             if(!empty($uid)){
  128.                 //调用获取组信息方法
  129.                 $group = $this->get_group($uid);
  130.                 //遍历组信息
  131.                 foreach($group as $v){
  132.                     //将组ID传入获取权限的方法
  133.                     $auth = $this->get_auth($v['gid']);    //获取该组的权限
  134.                 }
  135.                 //遍历该组的权限数组
  136.                 foreach($auth as $val){
  137.                     //将节点的ID传入获取节点信息方法
  138.                     $node[] = $this->get_node($val['nid']);    //获取节点的相关信息
  139.                 }
  140.                 //遍历节点数组,并拼装
  141.                 foreach($node as $nval){
  142.                     if($nval['pid']==0){
  143.                         $fnode[] = $nval;    //将控制器压入fnode数组
  144.                         //$cnode = $this->get_cnode($nval['id']);
  145.                     }else{
  146.                         $cnode[] = $nval;    //将控制器的方法压入cnode数组
  147.                     }
  148.                 }
  149.                 //将控制器数组和控制器数组拼装成一个数组
  150.                 foreach($fnode as $fval){
  151.                     foreach($cnode as $cval){
  152.                         if($cval['pid'] == $fval['id']){
  153.                             $access[$fval['name']][] = $cval['name'];
  154.                         }
  155.                     }
  156.                 }
  157.                 //返回权限列表数组
  158.                 return $access;
  159.             }else{
  160.                 return false;
  161.             }
  162.         }
  163.         
  164.         /*
  165.             检测权限方法
  166.             @param1 int 用户ID
  167.             @return boolean 权限禁止与否
  168.         */
  169.         
  170.         public function check($uid){
  171.             if(!empty($uid)){
  172.                 //将权限存入到$_SESSION['Access_List']中
  173.                 $_SESSION['Access_List'] = $this->get_access($uid);
  174.                 if(!empty($_GET['m'])){
  175.                     //判断此控制器是否被允许
  176.                     if(array_key_exists($_GET['m'],$_SESSION['Access_List'])){
  177.                         //判断此控制器的方法是否被允许
  178.                         if(in_array($_GET['a'],$_SESSION['Access_List'][$_GET['m']])){
  179.                             //允许的话返回真
  180.                             return true;
  181.                         }else{
  182.                             //否则返回假
  183.                             return false;
  184.                         }
  185.                     }else{
  186.                         return false;
  187.                     }
  188.                 }else{
  189.                     return false;
  190.                 }
  191.             }else{
  192.                 //$_SESSION['user_'.$uid]['Access_List'] = 0;
  193.                 return false;
  194.             }
  195.         }
  196.         
  197.         public function show_node(){
  198.             $path = APP_PATH.'/controls/';
  199.             $handle = opendir($path);
  200.             while(false!==($data = readdir($handle))){
  201.                 if(is_file($path.$data) && $data!='common.class.php' && $data!='pub.class.php'){
  202.                     $controller = str_replace(".class.php",'',$data);
  203.                     $res = fopen($path.$data,'r');
  204.                     $str = fread($res,filesize($path.$data));
  205.                     $pattern = '/function(.*)\(\)/iU';
  206.                     preg_match_all($pattern, $str, $matches);
  207.                     foreach($matches[1] as $v){
  208.                         $v = trim($v);
  209.                         $arr[$controller][] = $v;
  210.                     }
  211.                 }
  212.             }
  213.             closedir($handle);
  214.             return $arr;
  215.         }
  216.     }


初始化类:

  1. <?php
  2.     /*+---------------------------------------------------------------------------------------+
  3.       | 初始化控制器
  4.       +-----------------------------------------------------------------------------------------+
  5.       | 版权所有 lamp兄弟连                        
  6.       +-----------------------------------------------------------------------------------------+
  7.       | 作者: 李捷 (lijie@li-jie.me)                            
  8.       | 最后修改时间: 2012-05-06 18:30                                          
  9.       +-----------------------------------------------------------------------------------------+
  10.     */
  11.     class Common extends Action {
  12.         /*
  13.             初始化方法
  14.         */
  15.         public function init(){
  16.             //如果SESSION为空,则跳转
  17.             if(empty($_SESSION['user_login'])){
  18.                 $this->redirect("pub/index");
  19.             }
  20.             $a = new rbac();
  21.             if(!$a->check($_SESSION['user_info']['id'])){
  22.                 echo "<script>alert('您没有此权限!')</script>";
  23.                 exit("<script>document.write('<span style=\'font-size:40px;font-weight:bold\'>Access Forbidden');alert('您没有此权限!');</script>");
  24.                 $this->redirect("pub/index");
  25.                 
  26.             }
  27.         }
  28.     }

这里给大家写了一个简单的RBAC类,仅供大家学习参考此思想,如有问题可以跟帖回复....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值