php ci框架使用qeephp框架的acl实现权限验证

1、在libraries文件夹下添加Acl.php类库

View Code
  1 <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2 /**
  3  * ACL 实现了权限检查服务
  4  *
  5  * “基于角色”通过比对拥有的角色和访问需要的角色来决定是否通过权限检查。
  6  *
  7  * 在进行权限检查时,要求分别提供角色组和访问控制列表(ACL)。
  8  * 然后由 QACL 比对角色组和 ACL,并返回检查结果。
  9  *
 10  * rolesBasedCheck() 用于比对权限,并返回结果。
 11  * role_normalize() 方法用于将 roles 角色配置 转换为符合规范的 数组形式。
 12  * acl_normalize() 方法用于将 ACL 转换为符合规范的 ACL。
 13  */
 14 class Acl
 15 {
 16     /**
 17      * 预定义角色常量
 18      */
 19     const ACL_EVERYONE    = 'acl_everyone';
 20     const ACL_NULL        = 'acl_null';
 21     const ACL_NO_ROLE     = 'acl_no_role';
 22     const ACL_HAS_ROLE    = 'acl_has_role';
 23     const ALL_CONTROLLERS = 'all_controllers';
 24     const ALL_ACTIONS     = 'all_actions';
 25 
 26     var $uri = array('space'=>'','controller'=>'','action'=>'');
 27     var $acl;
 28     var $acl_controller;
 29     var $acl_action;
 30     var $roles;
 31 
 32     function __construct(){
 33         if(function_exists('get_instance') && class_exists('CI_Controller')){
 34             $CI =& get_instance();
 35             $this->uri = array(
 36                 'space' => $CI->router->fetch_directory(),
 37                 'controller' => $CI->router->fetch_class(),
 38                 'action' => $CI->router->fetch_method()
 39             );
 40         }
 41     }
 42     
 43     /**
 44      * 对 roles 进行权限验证
 45      * @param array $roles
 46      * @param array $acl_uri    space空间命名(CI中的controllers/下dir分目录)    controller控制器文件    action为控制器处理函数
 47      * @param array $acl        自定义权限验证配置
 48      * @return array
 49      */
 50     function checkAcl($roles, $uri = array(),$acl = array()){
 51         if(!empty($uri))    $this->uri = array_merge($this->uri,$uri);
 52         $acl_file = 'acl';
 53         if(isset($this->uri['space'])){
 54             if(!empty($this->uri['space'])){
 55                 $acl_file .= '_'.$this->uri['space'];
 56             }
 57         }
 58         if(empty($acl)){
 59             $filepath = APPPATH.'config/'.$acl_file.'.php';
 60             if (!file_exists($filepath)) return TRUE;
 61         }
 62         $this->roles = $this->roles_normalize($roles);
 63         include($filepath);
 64         $this->acl = $acl;
 65         $this->acl_controller = $this->_controllerACL($this->uri['controller']);
 66         return $this->_actionACL($this->uri['action']);
 67     }
 68     
 69     /**
 70      * 对 roles 整理,返回整理结果
 71      * @param array $roles
 72      * @return array
 73      */
 74     function roles_normalize($roles){
 75         if (!is_array($roles)){    $roles = explode(',', $roles);    }
 76         return array_map('strtolower',array_filter(array_map('trim',$roles),'strlen'));
 77     }
 78     
 79     /**
 80      * 对 ACL 整理,返回整理结果
 81      * @param array $acl 要整理的 ACL
 82      * @return array
 83      */
 84     function acl_normalize(array $acl){
 85         $acl = array_change_key_case($acl, CASE_LOWER);
 86         $ret = array();
 87         $keys = array('allow', 'deny');
 88         foreach ($keys as $key){
 89             do{
 90                 if (!isset($acl[$key])){    $values = self::ACL_NULL;    break;    }
 91                 $acl[$key] = strtolower($acl[$key]);
 92                 if($acl[$key] == self::ACL_EVERYONE || $acl[$key] == self::ACL_HAS_ROLE 
 93                 || $acl[$key] == self::ACL_NO_ROLE || $acl[$key] == self::ACL_NULL){
 94                     $values = $acl[$key];    break;
 95                 }
 96                 $values = $this->roles_normalize($acl[$key]);
 97                 if (empty($values)){    $values = self::ACL_NULL;    }
 98             }while (FALSE);
 99             $ret[$key] = $values;
100         }
101         return $ret;
102     }
103     
104     /**
105      * 对 controller 访问控制做处理
106      * @param string $controller
107      * @return array
108      */
109     protected function _controllerACL($controller){
110         if(isset($this->acl[$controller])){
111             $this->acl = array_change_key_case($this->acl, CASE_LOWER);
112             return (array)$this->acl[$controller];
113         }
114         return isset($this->acl[self::ALL_CONTROLLERS]) ? (array)$this->acl[self::ALL_CONTROLLERS]
115             : array('allow' => self::ACL_EVERYONE);
116     }
117         
118     /**
119      * 对 action 访问控制做处理
120      * @param string $action
121      * @return array
122      */
123     protected function _actionACL($action){
124         if(isset($this->acl_controller['actions'][$action])){
125             return $this->_rolesBasedCheck($this->acl_controller['actions'][$action]);
126         }
127         if(isset($this->acl_controller['actions'][self::ALL_ACTIONS])){
128             return $this->_rolesBasedCheck($this->acl_controller['actions'][self::ALL_ACTIONS]);
129         }
130         if(isset($this->acl_controller)){
131             return $this->_rolesBasedCheck($this->acl_controller);
132         }
133     }
134     
135     /**
136      * 进行实际权限校验
137      * @param string $acl
138      * @return array
139      */
140     protected function _rolesBasedCheck($acl){
141         $this->acl_action = $this->acl_normalize($acl);
142         if ($this->acl_action['allow'] == self::ACL_EVERYONE){
143             // 如果 allow 允许所有角色,deny 没有设置,则检查通过
144             if ($this->acl_action['deny'] == self::ACL_NULL){    return TRUE;    }
145 
146             // 如果 deny 为 acl_no_role,则只要用户具有角色就检查通过
147             if ($this->acl_action['deny'] == self::ACL_NO_ROLE){
148                 if (empty($this->roles)){    return FALSE;    }
149                 return TRUE;
150             }
151 
152             // 如果 deny 为 acl_has_role,则只有用户没有角色信息时才检查通过
153             if ($this->acl_action['deny'] == self::ACL_HAS_ROLE){
154                 if (empty($this->roles)){    return TRUE;    }
155                 return FALSE;
156             }
157 
158             // 如果 deny 也为 acl_everyone,则表示 acl 出现了冲突
159             if ($this->acl_action['deny'] == self::ACL_EVERYONE){
160                 return FALSE;
161             }
162 
163             // 只有 deny 中没有用户的角色信息,则检查通过
164             foreach ($this->roles as $role){
165                 if (in_array($role, $this->acl_action['deny'])){    return FALSE;    }
166             }
167             return TRUE;
168         }
169 
170         do{
171             // 如果 allow 要求用户具有角色,但用户没有角色时直接不通过检查
172             if ($this->acl_action['allow'] == self::ACL_HAS_ROLE){
173                 if (!empty($this->roles)){    break;    }
174                 return FALSE;
175             }
176 
177             // 如果 allow 要求用户没有角色,但用户有角色时直接不通过检查
178             if ($this->acl_action['allow'] == self::ACL_NO_ROLE){
179                 if (empty($this->roles)){    break;    }
180                 return FALSE;
181             }
182 
183             if ($this->acl_action['allow'] != self::ACL_NULL){
184                 // 如果 allow 要求用户具有特定角色,则进行检查
185                 $passed = FALSE;
186                 foreach ($this->roles as $role){
187                     if (in_array($role, $this->acl_action['allow'])){
188                         $passed = TRUE;
189                         break;
190                     }
191                 }
192                 if (!$passed){    return FALSE;    }
193             }
194         } while (FALSE);
195 
196         // 如果 deny 没有设置,则检查通过
197         if ($this->acl_action['deny'] == self::ACL_NULL){    return TRUE;    }
198 
199         // 如果 deny 为 acl_no_role,则只要用户具有角色就检查通过
200         if ($this->acl_action['deny'] == self::ACL_NO_ROLE){
201             if (empty($this->roles)){    return FALSE;    }
202             return TRUE;
203         }
204         // 如果 deny 为 acl_has_role,则只有用户没有角色信息时才检查通过
205         if ($this->acl_action['deny'] == self::ACL_HAS_ROLE){
206             if (empty($this->roles)){    return TRUE;    }
207             return FALSE;
208         }
209 
210         // 如果 deny 为 acl_everyone,则检查失败
211         if ($this->acl_action['deny'] == self::ACL_EVERYONE){    return FALSE;    }
212 
213         // 只有 deny 中没有用户的角色信息,则检查通过
214         foreach ($this->roles as $role){
215             if (in_array($role, $this->acl_action['deny'])){    return FALSE;    }
216         }
217         return TRUE;
218     }
219 }
220 // END Controller class
221 
222 /* End of file Acl.php */
223 /* Location: ./application/libraries/Acl.php */

 2、在项目文件夹下的core文件夹中创建核心类MY_Controller.php,在该文件中添加权限验证,所有需要验证的控制器文件都要继承该类。

 1 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 2 
 3 class Auth_Controller extends CI_Controller {
 4     
 5     var $role = '';
 6     var $uid = 0;
 7     var $username = '';
 8     
 9     var $_ckey='';
10     var $_akey='';
11     var $_mkey='';
12     
13     function __construct()
14     {
15         parent::__construct();
16                 //引入Acl类库
17         $this->load->library(array('Acl','common'));
18 
19         //假设现在角色为admin,这里可以自已定义获取角色权限的方法。
20                 $this->role = 'gm';
21                 //执行权限判断
22         if(!$this->acl->checkAcl( $this->role )){
23             if( method_exists($this,'_on_access_denied') ) $this->_on_access_denied();
24         }
25         
26         
27     }
28     
29     /*
30      * @name _on_access_denied 访问无权限时处理方法
31      * @return null
32      */
33     protected function _on_access_denied()
34     {
35         header('Content-type: text/html; charset=utf-8');
36         echo '无权限';exit;
37 //        header('Location: '.config_item('sso_admin_url').'?ref='.urlencode(config_item('ref_url')));exit;
38     }
39     
40     protected function _db_error(){
41         echo 'DB_error();';exit;
42     }
43     
44     protected function _redirectMessage($heading,$message,$url,$time=5,$hidden_script='')
45     {
46         $this->load->view('common/show_msg',array('message_caption'=>$heading,'message_body'=>$message,'redirect_url'=>$url,'redirect_delay'=>$time,'hidden_script'=>$hidden_script));
47         return;
48     }
49     
50     protected function _FailMessage($info,$msg,$url = array()){
51         if(is_array($url)) $url = $this->common->Get_Url($url);
52         return $this->_redirectMessage($this->common->Get_ErrorMsg($info),$this->common->Get_ErrorMsg($msg),$url);
53     }
54 }
55 // END Controller class
56 
57 /* End of file Auth_Controller.php */
58 /* Location: ./application/libraries/Auth_Controller.php */            

3、权限配置文件,在项目的config文件夹下添加acl.php文件,格式参考下面的示例代码。

该文件中配置了testacl控制器的访问权限为ACL_HAS_ROLE,即所有拥有角色的用户都有权限访问。

actions中配置的是testacl控制器中index方法和add方法的访问权限。“allow”表示可以访问的角色,“deny”表示不允许访问的角色。

 1 <?php
 2 if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 3 //遵循qeephp中的acl规则
 4 $acl['all_controllers'] = array(
 5     'allow'=>'ACL_HAS_ROLE',//表示所有拥有角色的用户
 6 );
 7 $acl['testacl'] = array(
 8     'allow'=>'ACL_HAS_ROLE',
 9     'actions'=>array(
10         'index'=>array('allow' => 'admin,editor,gm'),
11         'add' => array('allow'=> 'admin,editor'),
12     ),
13 );

Acl中预定义的角色常量如下:

 ACL_EVERYONE = 'acl_everyone';     // 所有用户

 ACL_NULL = 'acl_null';                     // 未设置

ACL_NO_ROLE = 'acl_no_role';         // 没有角色用户

ACL_HAS_ROLE = 'acl_has_role';     // 有角色用户

ALL_CONTROLLERS = 'all_controllers';   //  表示所有控制器

ALL_ACTIONS = 'all_actions';           //  表示所有控制器内的方法

4、测试一下,创建一个testacl.php文件,

 1 <?php
 2 class Testacl extends Auth_Controller {
 3     function __construct() {
 4         parent::__construct();
 5     }
 6     
 7     function index() {
 8         echo "index method";
 9     }
10     
11     function add() {
12         echo "添加页,只有管理员和编辑有权限操作";
13     }
14 }

运行结果:在MY_Controller中我们假设了role=“gm”,

     所以访问http://localhost/CodeIgniter_2.1.1/index.php?c=testacl&m=index时输出 "index method"

      而访问:http://localhost/CodeIgniter_2.1.1/index.php?c=testacl&m=add时输出 “无权限”。

 

posted @ 2013-03-20 16:30  欧麦噶地  阅读(1889)  评论(0编辑  收藏  举报