php中实现简单的ACL 完结篇


Posted in PHP onSeptember 07, 2011
-- ACL Tables 
-- 表的结构 `aclresources` 
DROP TABLE IF EXISTS `aclresources`; 
CREATE TABLE IF NOT EXISTS `aclresources` ( 
`rsid` varchar(64) NOT NULL , 
`access` int(4) NOT NULL default 0, 
`desc` varchar(240) NOT NULL default '', 
`created_at` int(10) unsigned NOT NULL default 1, 
`updated_at` int(10) unsigned NOT NULL default 0, 
PRIMARY KEY (`rsid`) 
)DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 
-- 表的结构 `aclroles` 
DROP TABLE IF EXISTS `aclroles`; 
CREATE TABLE IF NOT EXISTS `aclroles` ( 
`id` int(10) unsigned NOT NULL auto_increment, 
`rolename` varchar(32) NOT NULL , 
`desc` varchar(240) NOT NULL default '', 
`created_at` int(10) unsigned NOT NULL default 1, 
`updated_at` int(10) unsigned NOT NULL default 0, 
PRIMARY KEY (`id`), 
UNIQUE KEY `rolename` (`rolename`) 
)DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 
-- 表的结构 `ref_aclresources_aclroles` 
DROP TABLE IF EXISTS `ref_aclresources_aclroles`; 
CREATE TABLE IF NOT EXISTS `ref_aclresources_aclroles` ( 
`rsid` varchar(64) NOT NULL , 
`role_id` int(10) unsigned NOT NULL , 
PRIMARY KEY (`rsid`,`role_id`) 
)DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 
-- 表的结构 `ref_users_aclroles` 
DROP TABLE IF EXISTS `ref_users_aclroles`; 
CREATE TABLE IF NOT EXISTS `ref_users_aclroles` ( 
`user_id` int(10) unsigned NOT NULL auto_increment, 
`role_id` int(10) unsigned NOT NULL , 
PRIMARY KEY (`user_id`,`role_id`) 
)DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 
-- 表的结构 `users` 
DROP TABLE IF EXISTS `users`; 
CREATE TABLE `users` ( 
`id` int(10) unsigned NOT NULL auto_increment, 
`email` varchar(128) NOT NULL, 
`password` varchar(64) NOT NULL, 
`nickname` varchar(32) NOT NULL default '', 
`roles` varchar(240) NOT NULL default '', 
`created_at` int(10) unsigned NOT NULL default 1, 
`updated_at` int(10) unsigned NOT NULL default 0, 
PRIMARY KEY (`id`), 
UNIQUE KEY `user_email` (`email`) 
)DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

php 类
<?php 
/** 
* 简单的 ACL 权限控制功能 
* 
* 表定义 
* 
* 1. 资源定义 (rsid,access,desc,created_at,updated_at) 
* 2. 角色定义 (id,rolename,desc,created_at,updated_at) 
* 3. 资源-角色关联 (rsid,role_id) 
* 4. 用户-角色关联 (user_id,role_id) 
* 
* 依赖db.php sqlobject.php 
* 
* @author vb2005xu.iteye.com 
*/ 
class AclBase { 
// --- ACL 访问授权 /** 
* 不允许任何人访问 
*/ 
const NOBODY = 0; 
/** 
* 允许任何人访问 
*/ 
const EVERYONE = 1; 
/** 
* 允许 拥有角色的用户访问 
*/ 
const HAS_ROLE = 2; 
/** 
* 允许 不带有角色的用户访问 
*/ 
const NO_ROLE = 3; 
/** 
* 在 资源-角色关联 定义的 角色才能访问 
*/ 
const ALLOCATE_ROLES = 4; 
// 定义相关的 表名 
public $tbResources = 'aclresources'; 
public $tbRoles = 'aclroles'; 
public $tbRefResourcesRoles = 'ref_aclresources_aclroles'; 
public $tbRefUsersRoles = 'ref_users_aclroles'; 
/** 
* 格式化 资源的访问权限并返回 
* 
* @return int 
*/ 
static function formatAccessValue($access){ 
static $arr = array(self::NOBODY,self::EVERYONE,self::HAS_ROLE,self::NO_ROLE,self::ALLOCATE_ROLES); 
return in_array($access,$arr) ? $access : self::NOBODY; 
} 
/** 
* 创建资源,返回资源记录主键 
* 
* @param string $rsid 
* @param int $access 
* @param string $desc 
* 
* @return int 
*/ 
function createResource($rsid,$access,$desc){ 
if (empty($rsid)) return false; 
$resource = array( 
'rsid' => $rsid, 
'access' => self::formatAccessValue($access), 
'desc' => $desc, 
'created_at' => CURRENT_TIMESTAMP 
); 
return SingleTableCRUD::insert($this->tbResources,$resource); 
} 
/** 
* 修改资源,返回成功状态 
* 
* @param array $resource 
* @return int 
*/ 
function updateResource(array $resource){ 
if (!isset($resource['rsid'])) return false; 
$resource['updated_at'] = CURRENT_TIMESTAMP; 
return SingleTableCRUD::update($this->tbResources,$resource,'rsid'); 
} 
/** 
* 删除资源 
* 
* @param string $rsid 
* @return int 
*/ 
function deleteResource($rsid){ 
if (empty($rsid)) return false; 
return SingleTableCRUD::delete($this->tbResources,array('rsid'=>$rsid)); 
} 
/** 
* 创建角色,返回角色记录主键 
* 
* @param string $rolename 
* @param string $desc 
* 
* @return int 
*/ 
function createRole($rolename,$desc){ 
if (empty($rolename)) return false; 
$role = array( 
'rolename' => $rolename, 
'desc' => $desc, 
'created_at' => CURRENT_TIMESTAMP 
); 
return SingleTableCRUD::insert($this->tbRoles,$role); 
} 
/** 
* 修改角色,返回成功状态 
* 
* @param array $role 
* @return int 
*/ 
function updateRole(array $role){ 
if (!isset($role['id'])) return false; 
if (isset($role['rolename'])) unset($role['rolename']); 
$role['updated_at'] = CURRENT_TIMESTAMP; 
return SingleTableCRUD::update($this->tbRoles,$role,'id'); 
} 
/** 
* 删除角色 
* 
* @param int $role_id 
* @return int 
*/ 
function deleteRole($role_id){ 
if (empty($role_id)) return false; 
return SingleTableCRUD::delete($this->tbRoles,array('role_id'=>(int) $role_id)); 
} 
/** 
* 为资源指定角色,每次均先全部移除表中相关记录再插入 
* 
* @param int $rsid 
* @param mixed $roleIds 
* @param boolean $setNull 当角色id不存在时,是否将资源从关联表中清空 
*/ 
function allocateRolesForResource($rsid,$roleIds,$setNull=false,$defaultAccess=-1){ 
if (empty($rsid)) return false; 
$roleIds = normalize($roleIds,','); 
if (empty($roleIds)){ 
if ($setNull){ 
SingleTableCRUD::delete($this->tbRefResourcesRoles,array('rsid'=>$rsid)); 
if ($defaultAccess != -1){ 
$defaultAccess = self::formatAccessValue($defaultAccess); 
$this->updateResource(array('rsid'=>$rsid,'access'=>$defaultAccess)); 
} 
return true; 
} 
return false; 
} 
SingleTableCRUD::delete($this->tbRefResourcesRoles,array('rsid'=>$rsid)); 
$roleIds = array_unique($roleIds); 
foreach ($roleIds as $role_id){ 
SingleTableCRUD::insert($this->tbRefResourcesRoles,array('rsid'=>$rsid,'role_id'=>(int)$role_id)); 
} 
return true; 
} 
function cleanRolesForResource($rsid){ 
if (empty($rsid)) return false; 
return SingleTableCRUD::delete($this->tbRefResourcesRoles,array('rsid'=>$rsid)); 
} 
function cleanResourcesForRole($role_id){ 
if (empty($role_id)) return false; 
return SingleTableCRUD::delete($this->tbRefResourcesRoles,array('role_id'=>(int) $role_id)); 
} 
/** 
* 为角色分配资源,每次均先全部移除表中相关记录再插入 
* 
* @param int $role_id 
* @param mixed $rsids 
* 
* @return boolean 
*/ 
function allocateResourcesForRole($role_id,$rsids){ 
if (empty($role_id)) return false; 
$role_id = (int) $role_id; 
$rsids = normalize($rsids,','); 
if (empty($rsids)){ 
return false; 
} 
SingleTableCRUD::delete($this->tbRefResourcesRoles,array('role_id'=>$role_id)); 
$rsids = array_unique($rsids); 
foreach ($rsids as $rsid){ 
SingleTableCRUD::insert($this->tbRefResourcesRoles,array('rsid'=>$rsid,'role_id'=>$role_id)); 
} 
return true; 
} 
/** 
* 为用户指派角色,每次均先全部移除表中相关记录再插入 
* 
* 此处在用户很多的时候可能会有性能问题 ... 后面再想怎么优化 
* 
* @param int $user_id 
* @param mixed $roleIds 
* 
* @return boolean 
*/ 
function allocateRolesForUser($user_id,$roleIds){ 
if (empty($user_id)) return false; 
$user_id = (int) $user_id; 
$roleIds = normalize($roleIds,','); 
if (empty($roleIds)){ 
return false; 
} 
SingleTableCRUD::delete($this->tbRefUsersRoles,array('user_id'=>$user_id)); 
$roleIds = array_unique($roleIds); 
foreach ($roleIds as $roleId){ 
SingleTableCRUD::insert($this->tbRefUsersRoles,array('user_id'=>$user_id,'role_id'=>$role_id)); 
} 
return true; 
} 
/** 
* 清除用户的角色信息 
* 
* @param int $user_id 
* 
* @return boolean 
*/ 
function cleanRolesForUser($user_id){ 
if (empty($user_id)) return false; 
return SingleTableCRUD::delete($this->tbRefUsersRoles,array('user_id'=>(int) $user_id)); 
} 
/** 
* 清除角色的用户关联 
* 
* @param int $role_id 
* 
* @return boolean 
*/ 
function cleanUsersForRole($role_id){ 
if (empty($role_id)) return false; 
return SingleTableCRUD::delete($this->tbRefUsersRoles,array('role_id'=>(int) $role_id)); 
} 
}

具体 检测的代码 如下:
/** 
* 对资源进行acl校验 
* 
* @param string $rsid 资源标识 
* @param array $user 特定用户,不指定则校验当前用户 
* 
* @return boolean 
*/ 
function aclVerity($rsid ,array $user = null){ if (empty($rsid)) return false; 
if (!CoreApp::$defaultAcl) { 
CoreApp::$defaultAcl = new AclFlat(); 
} 
$rsRow = aclGetResource($rsid); 
// 未定义资源的缺省访问策略 
if (!$rsRow) return false; 
CoreApp::writeLog($rsRow,'test'); 
$rsRow['access'] = AclBase::formatAccessValue($rsRow['access']); 
// 允许任何人访问 
if (AclBase::EVERYONE == $rsRow['access']) return true; 
// 不允许任何人访问 
if (AclBase::NOBODY == $rsRow['access']) return false; 
// 获取用户信息 
if (empty($user)) $user = isset($_SESSION['SI-SysUser']) ? $_SESSION['SI-SysUser'] : null; 
// 用户未登录,则当成无访问权限 
if (empty($user)) return false; 
$user['roles'] = empty($user['roles']) ? null : normalize($user['roles'],';'); 
$userHasRoles = !empty($user['roles']); 
/** 
* 允许 不带有角色的用户访问 
*/ 
if (AclBase::NO_ROLE == $rsRow['access']) return $userHasRoles ? false : true; 
/** 
* 允许 带有角色的用户访问 
*/ 
if (AclBase::HAS_ROLE == $rsRow['access']) return $userHasRoles ? true : false; 
// --- 对用户进行 资源 <-> 角色 校验 
if ($userHasRoles){ 
foreach ($user['roles'] as $role_id){ 
if ( aclGetRefResourcesRoles($rsid,$role_id) ) 
return true; 
} 
dump($user); 
} 
return false; 
}

/** 
* 对资源进行acl校验 
* 
* @param string $rsid 资源标识 
* @param array $user 特定用户,不指定则校验当前用户 
* 
* @return boolean 
*/ 
function aclVerity($rsid ,array $user = null){ if (empty($rsid)) return false; 
if (!CoreApp::$defaultAcl) { 
CoreApp::$defaultAcl = new AclFlat(); 
} 
$rsRow = aclGetResource($rsid); 
// 未定义资源的缺省访问策略 
if (!$rsRow) return false; 
CoreApp::writeLog($rsRow,'test'); 
/* 
* 校验步骤如下: 
* 
* 1. 先校验 资源本身 access 属性 
* EVERYONE => true,NOBODY => false * 其它的属性在下面继续校验 
* 2. 从 session(或者 用户session表)中获取角色id集合 
* 3. 如果 用户拥有角色 则 HAS_ROLE => true , NO_ROLE => false;反之亦然 
* 4. 如果资源 access == ALLOCATE_ROLES 
* 1. 从缓存(或者 $tbRefResourcesRoles)中获取 资源对应的角色id集合 
* 2. 将用户拥有的角色id集合 与 资源对应的角色id集合求交集 
* 3. 存在交集 => true;否则 => false 
*/ 
$rsRow['access'] = AclBase::formatAccessValue($rsRow['access']); 
// 允许任何人访问 
if (AclBase::EVERYONE == $rsRow['access']) return true; 
// 不允许任何人访问 
if (AclBase::NOBODY == $rsRow['access']) return false; 
// 获取用户信息 
if (empty($user)) $user = isset($_SESSION['SI-SysUser']) ? $_SESSION['SI-SysUser'] : null; 
// 用户未登录,则当成无访问权限 
if (empty($user)) return false; 
$user['roles'] = empty($user['roles']) ? null : normalize($user['roles'],';'); 
$userHasRoles = !empty($user['roles']); 
/** 
* 允许 不带有角色的用户访问 
*/ 
if (AclBase::NO_ROLE == $rsRow['access']) return $userHasRoles ? false : true; 
/** 
* 允许 带有角色的用户访问 
*/ 
if (AclBase::HAS_ROLE == $rsRow['access']) return $userHasRoles ? true : false; 
// --- 对用户进行 资源 <-> 角色 校验 
if ($userHasRoles){ 
foreach ($user['roles'] as $role_id){ 
if ( aclGetRefResourcesRoles($rsid,$role_id) ) 
return true; 
} 
dump($user); 
} 
return false; 
} 
/** 
* 重新生成 角色资源访问控制表 
* 
* @param string $actTable ACL表名称 
* @param boolean $return 是否返回重新生成的列表 
* 
* @return mixed 
*/ 
function aclRebuildACT($actTable ,$return = false){ 
if (empty($actTable)) return false; 
global $globalConf; 
$rst = null; 
$cacheId = null; 
switch($actTable){ 
case CoreApp::$defaultAcl->tbResources: 
$cacheId = 'acl-resources'; 
$rst = SingleTableCRUD::findAll(CoreApp::$defaultAcl->tbResources); 
// 转成 哈希表结构 
if ($rst){ 
$rst = array_to_hashmap($rst,'rsid'); 
} 
break; 
case CoreApp::$defaultAcl->tbRoles: 
$cacheId = 'acl-roles'; 
$rst = SingleTableCRUD::findAll(CoreApp::$defaultAcl->tbRoles); 
// 转成 哈希表结构 
if ($rst){ 
$rst = array_to_hashmap($rst,'id'); 
} 
break; 
case CoreApp::$defaultAcl->tbRefResourcesRoles: 
$cacheId = 'acl-roles_has_resources'; 
$rst = SingleTableCRUD::findAll(CoreApp::$defaultAcl->tbRefResourcesRoles); 
if ($rst){ 
$_ = array(); 
foreach ($rst as $row) { 
$ref_id = "{$row['rsid']}<-|->{$row['role_id']}"; 
$_[$ref_id] = $row; 
} 
unset($rst); 
$rst = $_; 
} 
break; 
} 
if ($cacheId) 
writeCache($globalConf['runtime']['cacheDir'] ,$cacheId ,$rst ,true); 
if ($return) return $rst; 
} 
/** 
* 获取 角色资源访问控制表 数据 
* 
* @param string $actTable ACL表名称 
* 
* @return mixed 
*/ 
function aclGetACT($actTable){ 
if (empty($actTable)) return false; 
static $rst = array(); 
$cacheId = null; 
switch($actTable){ 
case CoreApp::$defaultAcl->tbResources: 
$cacheId = 'acl-resources'; 
break; 
case CoreApp::$defaultAcl->tbRoles: 
$cacheId = 'acl-roles'; 
break; 
case CoreApp::$defaultAcl->tbRefResourcesRoles: 
$cacheId = 'acl-roles_has_resources'; 
break; 
} 
if (!$cacheId) return null; 
if (isset($rst[$cacheId])) return $rst[$cacheId]; 
global $globalConf; 
// 900 
$rst[$cacheId] = getCache($globalConf['runtime']['cacheDir'],$cacheId,0); 
if ( !$rst[$cacheId] ){ 
$rst[$cacheId] = aclRebuildACT($actTable,true); 
} 
return $rst[$cacheId]; 
} 
/** 
* 获取 资源 记录 
* 
* @param string $rsid 
* 
* @return array 
*/ 
function aclGetResource($rsid){ 
static $rst = null; 
if (!$rst){ 
$rst = aclGetACT(CoreApp::$defaultAcl->tbResources); 
if (!$rst) $rst = array(); 
} 
return isset($rst[$rsid]) ? $rst[$rsid] : null; 
} 
/** 
* 获取 角色 记录 
* 
* @param int $role_id 
* 
* @return array 
*/ 
function aclGetRole($role_id){ 
static $rst = null; 
if (!$rst){ 
$rst = aclGetACT(CoreApp::$defaultAcl->tbRoles); 
if (!$rst) $rst = array(); 
} 
return isset($rst[$role_id]) ? $rst[$role_id] : null; 
} 
/** 
* 获取 用户角色关联 记录,此方法可以校验资源是否可被此角色调用 
* 
* @param string $rsid 
* @param int $role_id 
* 
* @return array 
*/ 
function aclGetRefResourcesRoles($rsid,$role_id){ 
static $rst = null; 
if (!$rst){ 
$rst = aclGetACT(CoreApp::$defaultAcl->tbRefResourcesRoles); 
if (!$rst) $rst = array(); 
} 
$ref_id = "{$rsid}<-|->{$role_id}"; 
CoreApp::writeLog(isset($rst[$ref_id])?$rst[$ref_id]:'nodata',$ref_id); 
return isset($rst[$ref_id]) ? $rst[$ref_id] : null; 
}

http://code.google.com/p/php-excel/downloads/list 迷你好用的 EXCEL xml 输出方案
PHP 相关文章推荐
第十节 抽象方法和抽象类 [10]
Oct 09 PHP
PHP入门学习的几个不错的实例代码
Jul 13 PHP
Apache 配置详解(最好的APACHE配置教程)
Jul 04 PHP
如何突破PHP程序员的技术瓶颈分析
Jul 17 PHP
PHP写的获取各搜索蜘蛛爬行记录代码
Aug 21 PHP
PHP中的日期加减方法示例
Aug 21 PHP
调试PHP程序的多种方法介绍
Nov 06 PHP
symfony表单与页面实现技巧
Jan 26 PHP
PHP实现数组转JSon和JSon转数组的方法示例
Jun 14 PHP
PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
Sep 08 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
Nov 26 PHP
is_file和file_exists效率比较
Mar 14 PHP
php将时间差转换为字符串提示
Sep 07 #PHP
php 中英文语言转换类
Sep 07 #PHP
php继承的一个应用
Sep 06 #PHP
php 抽象类的简单应用
Sep 06 #PHP
PHP中PDO基础教程 入门级
Sep 04 #PHP
PHP中PDO的错误处理
Sep 04 #PHP
php中将网址转换为超链接的函数
Sep 02 #PHP
You might like
laravel安装和配置教程
2014/10/29 PHP
php防止sql注入简单分析
2015/03/18 PHP
jquery 表单下所有元素的隐藏
2009/07/25 Javascript
用JS写的一个TableView控件代码
2010/01/23 Javascript
用JQuery实现表格隔行变色和突出显示当前行的代码
2012/02/10 Javascript
JS实现悬浮移动窗口(悬浮广告)的特效
2013/03/12 Javascript
向当前style sheet中插入一个新的style实现方法
2013/04/01 Javascript
使用Jquery实现点击文字后变成文本框且可修改
2013/09/21 Javascript
javascript实现相同事件名称,不同命名空间的调用方法
2015/06/26 Javascript
jQuery EasyUI封装简化操作
2016/09/18 Javascript
jQuery+ThinkPHP+Ajax实现即时消息提醒功能实例代码
2017/03/21 jQuery
Javascript操作dom对象之select全面解析
2017/04/24 Javascript
underscore之Collections_动力节点Java学院整理
2017/07/10 Javascript
vue框架搭建之axios使用教程
2018/07/11 Javascript
JS实现字符串翻转的方法分析
2018/08/31 Javascript
详解JavaScript作用域和作用域链
2019/03/19 Javascript
微信小程序与公众号卡券/会员打通的问题
2019/07/25 Javascript
简介JavaScript错误处理机制
2020/08/04 Javascript
vue 实现基础组件的自动化全局注册
2020/12/25 Vue.js
浅析Python中else语句块的使用技巧
2016/06/16 Python
python获取指定时间差的时间实例详解
2017/04/11 Python
在pycharm 中添加运行参数的操作方法
2019/01/19 Python
详解pandas数据合并与重塑(pd.concat篇)
2019/07/09 Python
python遍历文件目录、批量处理同类文件
2019/08/31 Python
pd.DataFrame统计各列数值多少的实例
2019/12/05 Python
Python如何根据时间序列数据作图
2020/05/12 Python
最新教师自我评价分享
2013/11/12 职场文书
2014年社区学雷锋活动总结
2014/03/09 职场文书
我们的节日春节活动方案
2014/08/22 职场文书
幼儿园个人师德总结
2015/02/06 职场文书
学校趣味运动会开幕词
2016/03/04 职场文书
教您:房贷工资收入证明应该怎么写?
2019/08/19 职场文书
Vue3.0 手写放大镜效果
2021/07/25 Vue.js
分布式架构Redis中有哪些数据结构及底层实现原理
2022/03/13 Redis
Smart 2 车辆代号 HC11 全新谍照曝光
2022/04/21 数码科技
Spring JPA 增加字段执行异常问题及解决
2022/06/10 Java/Android