/**

* 简单的 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));

}

}

/**

* AclFlat 弱化了 用户-角色 的管理,在用户表中存储了roles信息

*

* 用户-角色关联 user(id,roles)

*/

class AclFlat extends AclBase {

public $tbRefUsersRoles = 'users';

/**

* 为用户指派角色,每次均先全部移除表中相关记录再插入

*

* 在 用户表中增加 字段 roles 来取代 AclBase 中的 关联表

* 解决父类中用户量大情况的性能问题的一种备用方案

*

* @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;

}

$roleIds = array_unique($roleIds);

// 为了获取某角色对应的用户列表,在存入用户角色时 使用 [;role_id;role_id;role_id;role_id;] 的格式

// 在查找时则可以 使用 like '%;13;%' 来查询

$roles = sprintf(';%s;',implode(';',$roleIds));

return SingleTableCRUD::update($this->tbRefUsersRoles,array('id'=>$user_id,'roles'=>$roles));

}

/**

* 清除用户的角色信息

*

* @param int $user_id

*

* @return boolean

*/

function cleanRolesForUser($user_id){

if (empty($user_id)) return false;

return SingleTableCRUD::update($this->tbRefUsersRoles,array('id'=>(int) $user_id,'roles'=>''));

}

/**

* 清除角色的用户关联

*

* @param int $role_id

*

* @return boolean

*/

function cleanUsersForRole($role_id){

throw new Exception('方法未实现: ' . get_class($this) . '->cleanUsersForRole($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();

}

return true;

$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;

}

php acl控制,用PHP怎么实现一个ACL系统?相关推荐

  1. h3c使用acl控制ftp访问_H3C访问控制列表(ACL)实例精华

    4.访问控制列表(ACL) (1)标准 RouterA [H3C]interface e0/0 [H3C-ethernet e0/0]ip address 192.168.1.1 255.255.25 ...

  2. 项目实战4—HAProxy实现高级负载均衡实战和ACL控制

    分类: Linux架构篇 转自https://www.cnblogs.com/along21/  haproxy实现高级负载均衡实战 环境:随着公司业务的发展,公司负载均衡服务已经实现四层负载均衡,但 ...

  3. ACL控制访问列表原理+实验

    ACL控制访问列表原理+实验 1.原理:ACL使用包过滤技术,在路由器上读取ISO七层模型的第三层及第四层包头中的信息,如源地址,目的地址,源端口,目的端口等,根据预先定义好的规则,对包头进行过滤. ...

  4. 第21节 ACL——控制路由器上接口大门的进出规则

    这里写目录标题 1 ACL概述 2 ACL分类及原理 2.1 标准ACL 2.2 扩展ACL 2.3 原理 3 ACL编辑 4 命名ACL 5 总结 6 参考文献 1 ACL概述 定义:Access ...

  5. centos将某一目录权限给用户_CenTOS7使用ACL控制目录权限,只给某个用户访问特定目录...

    前言 Linux 基本的权限控制仅可以对所属用户.所属组.其他用户进行的权限控制,而不能精确地控制每个用户的权限.ACL 规则就是用来解决这个问题的. 使用 ACL 规则,我们可以针对单一账户设置文件 ...

  6. FX5u控制4个伺服,一个完整的项目 程序用 标签分层,说明了定位控制中的公共参数设定、回原点、

    FX5u控制4个伺服,一个完整的项目 程序用 标签分层,说明了定位控制中的公共参数设定.回原点.JOG手动.绝对定位.相对定位.控制等部分,威纶程序报警界面.多个机种选择,手动,自动,暂停,包括有: ...

  7. FX5u控制4个伺服,一个完整的项目 回原点、JOG手动、绝对定位、相对定位、控制等部分

    FX5u控制4个伺服,一个完整的项目 程序用 标签分层,说明了定位控制中的公共参数设定.回原点.JOG手动.绝对定位.相对定位.控制等部分,威纶程序报警界面.多个机种选择,手动,自动,暂停,包括有: ...

  8. linux主机设备acl,linux上的终端类型、ACL、PAM模块

    1. linux的ACL ACL可以针对单一用户.单一文件或目录进行设置r.w.x的权限设置,对于需要使用特殊权限的使用状况非常有帮助.首先需要查看系统是否支持acl ACL的设置技巧 getfacl ...

  9. 一个复杂系统的拆分改造,压力真大!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者 | zhanlijun 来源 | https://w ...

最新文章

  1. JAVA中equals空_Java中为什么查询空字符串跟判断是否为null的时候可以不用equals?...(亲测)
  2. kubernetes精华问答 | Swarm和K8S的共同点有哪些?
  3. OpenVINO InferenceEngine之读取IR
  4. DbNetSpell
  5. Focus Stacking
  6. row_number() over
  7. EMNLPICLR 多模态学习前沿分享
  8. 【Java】0X002 Hello World
  9. 计算机网络技术提纲,计算机网络技术复习提纲
  10. MaskFlownet图
  11. IRQL Ring0实现
  12. 支付宝统一收单接口实现支付宝支付
  13. 微信小程序开发者工具 无法加载以下来源的扩展程序 问题解决
  14. 超过2t硬盘分区_大于2T的磁盘怎么分区呢?
  15. SentiLR:Linguistic Knowledge Enhanced Language Representation for Sentiment Analysis 论文阅读笔记
  16. 燕十八PHP公益课堂学习笔记
  17. win10+python3.66+vs2017+cuda9.2下运行tensorflow版的faster-Rcnn编译训练
  18. ArrayList.toArray(T[] a) 的说明
  19. Java中线程池详解
  20. 解密「UWB」精准定位黑科技

热门文章

  1. CSDN博客的创建及使用
  2. 搜索算法,一触即达:GitHub上有个规模最大的开源算法库
  3. 马斯克员工参与新冠研究,论文登上Nature子刊
  4. 面试AI Lab能力测评
  5. 推荐一位我的好朋友,8年码农,前鹅厂工程师!
  6. CVPR2020 | 为尾部样本构造特征云,就像用电子云填充空旷的原子——长尾数据上的特征学习方法...
  7. 异步爬虫框架与协程浅析
  8. 爬虫基础(一)之概念、作用、分类和流程
  9. 论文速递 | 一份超全易懂的深度学习在图像去噪的综述
  10. 面试官:连YOLO都搞不定,是自己走还是我送你