您的位置:首页 > 编程语言 > PHP开发

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

2013-03-20 16:30 776 查看
1、在libraries文件夹下添加Acl.php类库

View Code

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* ACL 实现了权限检查服务
*
* “基于角色”通过比对拥有的角色和访问需要的角色来决定是否通过权限检查。
*
* 在进行权限检查时,要求分别提供角色组和访问控制列表(ACL)。
* 然后由 QACL 比对角色组和 ACL,并返回检查结果。
*
* rolesBasedCheck() 用于比对权限,并返回结果。
* role_normalize() 方法用于将 roles 角色配置 转换为符合规范的 数组形式。
* acl_normalize() 方法用于将 ACL 转换为符合规范的 ACL。
*/
class Acl
{
/**
* 预定义角色常量
*/
const ACL_EVERYONE    = 'acl_everyone';
const ACL_NULL        = 'acl_null';
const ACL_NO_ROLE     = 'acl_no_role';
const ACL_HAS_ROLE    = 'acl_has_role';
const ALL_CONTROLLERS = 'all_controllers';
const ALL_ACTIONS     = 'all_actions';

var $uri = array('space'=>'','controller'=>'','action'=>'');
var $acl;
var $acl_controller;
var $acl_action;
var $roles;

function __construct(){
if(function_exists('get_instance') && class_exists('CI_Controller')){
$CI =& get_instance();
$this->uri = array(
'space' => $CI->router->fetch_directory(),
'controller' => $CI->router->fetch_class(),
'action' => $CI->router->fetch_method()
);
}
}

/**
* 对 roles 进行权限验证
* @param array $roles
* @param array $acl_uri    space空间命名(CI中的controllers/下dir分目录)    controller控制器文件    action为控制器处理函数
* @param array $acl        自定义权限验证配置
* @return array
*/
function checkAcl($roles, $uri = array(),$acl = array()){
if(!empty($uri))    $this->uri = array_merge($this->uri,$uri);
$acl_file = 'acl';
if(isset($this->uri['space'])){
if(!empty($this->uri['space'])){
$acl_file .= '_'.$this->uri['space'];
}
}
if(empty($acl)){
$filepath = APPPATH.'config/'.$acl_file.'.php';
if (!file_exists($filepath)) return TRUE;
}
$this->roles = $this->roles_normalize($roles);
include($filepath);
$this->acl = $acl;
$this->acl_controller = $this->_controllerACL($this->uri['controller']);
return $this->_actionACL($this->uri['action']);
}

/**
* 对 roles 整理,返回整理结果
* @param array $roles
* @return array
*/
function roles_normalize($roles){
if (!is_array($roles)){    $roles = explode(',', $roles);    }
return array_map('strtolower',array_filter(array_map('trim',$roles),'strlen'));
}

/**
* 对 ACL 整理,返回整理结果
* @param array $acl 要整理的 ACL
* @return array
*/
function acl_normalize(array $acl){
$acl = array_change_key_case($acl, CASE_LOWER);
$ret = array();
$keys = array('allow', 'deny');
foreach ($keys as $key){
do{
if (!isset($acl[$key])){    $values = self::ACL_NULL;    break;    }
$acl[$key] = strtolower($acl[$key]);
if($acl[$key] == self::ACL_EVERYONE || $acl[$key] == self::ACL_HAS_ROLE
|| $acl[$key] == self::ACL_NO_ROLE || $acl[$key] == self::ACL_NULL){
$values = $acl[$key];    break;
}
$values = $this->roles_normalize($acl[$key]);
if (empty($values)){    $values = self::ACL_NULL;    }
}while (FALSE);
$ret[$key] = $values;
}
return $ret;
}

/**
* 对 controller 访问控制做处理
* @param string $controller
* @return array
*/
protected function _controllerACL($controller){
if(isset($this->acl[$controller])){
$this->acl = array_change_key_case($this->acl, CASE_LOWER);
return (array)$this->acl[$controller];
}
return isset($this->acl[self::ALL_CONTROLLERS]) ? (array)$this->acl[self::ALL_CONTROLLERS]
: array('allow' => self::ACL_EVERYONE);
}

/**
* 对 action 访问控制做处理
* @param string $action
* @return array
*/
protected function _actionACL($action){
if(isset($this->acl_controller['actions'][$action])){
return $this->_rolesBasedCheck($this->acl_controller['actions'][$action]);
}
if(isset($this->acl_controller['actions'][self::ALL_ACTIONS])){
return $this->_rolesBasedCheck($this->acl_controller['actions'][self::ALL_ACTIONS]);
}
if(isset($this->acl_controller)){
return $this->_rolesBasedCheck($this->acl_controller);
}
}

/**
* 进行实际权限校验
* @param string $acl
* @return array
*/
protected function _rolesBasedCheck($acl){
$this->acl_action = $this->acl_normalize($acl);
if ($this->acl_action['allow'] == self::ACL_EVERYONE){
// 如果 allow 允许所有角色,deny 没有设置,则检查通过
if ($this->acl_action['deny'] == self::ACL_NULL){    return TRUE;    }

// 如果 deny 为 acl_no_role,则只要用户具有角色就检查通过
if ($this->acl_action['deny'] == self::ACL_NO_ROLE){
if (empty($this->roles)){    return FALSE;    }
return TRUE;
}

// 如果 deny 为 acl_has_role,则只有用户没有角色信息时才检查通过
if ($this->acl_action['deny'] == self::ACL_HAS_ROLE){
if (empty($this->roles)){    return TRUE;    }
return FALSE;
}

// 如果 deny 也为 acl_everyone,则表示 acl 出现了冲突
if ($this->acl_action['deny'] == self::ACL_EVERYONE){
return FALSE;
}

// 只有 deny 中没有用户的角色信息,则检查通过
foreach ($this->roles as $role){
if (in_array($role, $this->acl_action['deny'])){    return FALSE;    }
}
return TRUE;
}

do{
// 如果 allow 要求用户具有角色,但用户没有角色时直接不通过检查
if ($this->acl_action['allow'] == self::ACL_HAS_ROLE){
if (!empty($this->roles)){    break;    }
return FALSE;
}

// 如果 allow 要求用户没有角色,但用户有角色时直接不通过检查
if ($this->acl_action['allow'] == self::ACL_NO_ROLE){
if (empty($this->roles)){    break;    }
return FALSE;
}

if ($this->acl_action['allow'] != self::ACL_NULL){
// 如果 allow 要求用户具有特定角色,则进行检查
$passed = FALSE;
foreach ($this->roles as $role){
if (in_array($role, $this->acl_action['allow'])){
$passed = TRUE;
break;
}
}
if (!$passed){    return FALSE;    }
}
} while (FALSE);

// 如果 deny 没有设置,则检查通过
if ($this->acl_action['deny'] == self::ACL_NULL){    return TRUE;    }

// 如果 deny 为 acl_no_role,则只要用户具有角色就检查通过
if ($this->acl_action['deny'] == self::ACL_NO_ROLE){
if (empty($this->roles)){    return FALSE;    }
return TRUE;
}
// 如果 deny 为 acl_has_role,则只有用户没有角色信息时才检查通过
if ($this->acl_action['deny'] == self::ACL_HAS_ROLE){
if (empty($this->roles)){    return TRUE;    }
return FALSE;
}

// 如果 deny 为 acl_everyone,则检查失败
if ($this->acl_action['deny'] == self::ACL_EVERYONE){    return FALSE;    }

// 只有 deny 中没有用户的角色信息,则检查通过
foreach ($this->roles as $role){
if (in_array($role, $this->acl_action['deny'])){    return FALSE;    }
}
return TRUE;
}
}
// END Controller class

/* End of file Acl.php */
/* Location: ./application/libraries/Acl.php */


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

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Auth_Controller extends CI_Controller {

var $role = '';
var $uid = 0;
var $username = '';

var $_ckey='';
var $_akey='';
var $_mkey='';

function __construct()
{
parent::__construct();
//引入Acl类库
$this->load->library(array('Acl','common'));

//假设现在角色为admin,这里可以自已定义获取角色权限的方法。
$this->role = 'gm';
//执行权限判断
if(!$this->acl->checkAcl( $this->role )){
if( method_exists($this,'_on_access_denied') ) $this->_on_access_denied();
}

}

/*
* @name _on_access_denied 访问无权限时处理方法
* @return null
*/
protected function _on_access_denied()
{
header('Content-type: text/html; charset=utf-8');
echo '无权限';exit;
//        header('Location: '.config_item('sso_admin_url').'?ref='.urlencode(config_item('ref_url')));exit;
}

protected function _db_error(){
echo 'DB_error();';exit;
}

protected function _redirectMessage($heading,$message,$url,$time=5,$hidden_script='')
{
$this->load->view('common/show_msg',array('message_caption'=>$heading,'message_body'=>$message,'redirect_url'=>$url,'redirect_delay'=>$time,'hidden_script'=>$hidden_script));
return;
}

protected function _FailMessage($info,$msg,$url = array()){
if(is_array($url)) $url = $this->common->Get_Url($url);
return $this->_redirectMessage($this->common->Get_ErrorMsg($info),$this->common->Get_ErrorMsg($msg),$url);
}
}
// END Controller class

/* End of file Auth_Controller.php */
/* Location: ./application/libraries/Auth_Controller.php */


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

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

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

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


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文件,

<?php
class Testacl extends Auth_Controller {
function __construct() {
parent::__construct();
}

function index() {
echo "index method";
}

function add() {
echo "添加页,只有管理员和编辑有权限操作";
}
}


运行结果:在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时输出 “无权限”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: