如何缓存 CakePHP Db ACL 检查
在将 SQL 查询日志记录到 Chrome 控制台中后,我开始注意到对 ARO 表的查询运行速度为 300 毫秒或更长。这些数据不会经常更改,并且每次请求都需要,因此它是缓存的理想选择。不幸的是,我找不到任何缓存 DbAcl 检查的机制。这是我的解决方案。
CacheDbAcl
这相当简单。首先在 app/Lib/CacheDbAcl.php 中创建一个新文件,并 复制并粘贴代码 (超链接) 或查看文章底部。
接下来将以下配置添加到 app/Config/bootstrap.php:Configure::write(‘CacheDbAclConfig’,’default’); > Configure::write(‘CacheDbAclAro’,’User.UserGroup’);<br > > <p>现在在 app Config/core.php 中添加或编辑以下内容:Configure::write(‘Acl.classname’, ‘CacheDbAcl’); ><br > 代码说明
CacheDbAcl 库与 CakePHP 2.x 附带的 DbAcl 库的功能完全相同。唯一更改的是 check() 方法。它的作用
- CacheDbAcl 验证是否启用了缓存。如果未启用,它将恢复正常操作。
- 读取要使用的缓存配置名称,请参见 CacheDbAclConfig。
- 检查要使用 ARO 的哪一部分作为缓存键(稍后详细介绍),请参见 CacheDbAclAro。
- 检查缓存中是否存在 Aro、Aco 和 Action 的条目。如果不存在,它将执行其正常操作,然后缓存结果。否则,它只从缓存中读取。
关于 CacheDbAclAro 设置的更多信息
由于传递到 DbAcl::check 的 ARO 数组可能因您的数据库结构和应用程序要求而异,因此我允许您设置 ARO 的哪一部分用作唯一的缓存键。如果您希望为每个用户创建缓存,只需完全不设置此设置。
如果您只希望为每个组创建缓存条目,请使用类似于我上面发布的内容。也许您有一个特殊用例,只希望使用 ARO 的非常特定部分作为键,这为您提供了这种灵活性。
我为这个应用程序选择了 User.UserGroup,因为我们的权限是基于组的,我希望减少创建的缓存条目的总数。当组的权限发生更改时,UserGroups 模型中的 modified 字段将自然地更新,因此新的缓存条目将自动创建,而旧的缓存条目将最终过期。
/**
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Chris Nizzardini
* @link https://cakephp.com.cn CakePHP(tm) Project
* @package Cake.Controller.Component.Acl
* @license MIT License (https://www.opensource.org/licenses/mit-license.php)
*/
App::uses('AclInterface', 'Controller/Component/Acl');
App::uses('Hash', 'Utility');
App::uses('ClassRegistry', 'Utility');
/**
* CacheDbAcl works the exact sabe as DbAcl expect that it will cache the results to using a cache config of your choosing:
* - Configurations in bootstrap.php:
* App::uses('CacheDbAcl', 'Lib');
* Configure::write('CacheDbAclConfig','Name_of_Your_Cache_Config')
* Configure::write('CacheDbAclAro','YourArrayKey.YourArray');
*
* - Configurations in core.php:
* Configure::write('Acl.classname', 'CacheDbAcl');
*
* @package Cake.Controller.Component.Acl
*/
class CacheDbAcl extends Object implements AclInterface {
/**
* Constructor
*
*/
public function __construct() {
parent::__construct();
$this->Permission = ClassRegistry::init(array('class' => 'Permission', 'alias' => 'Permission'));
$this->Aro = $this->Permission->Aro;
$this->Aco = $this->Permission->Aco;
}
/**
* Initializes the containing component and sets the Aro/Aco objects to it.
*
* @param AclComponent $component
* @return void
*/
public function initialize(Component $component) {
$component->Aro = $this->Aro;
$component->Aco = $this->Aco;
}
/**
* Checks if the given $aro has access to action $action in $aco
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success (true if ARO has access to action in ACO, false otherwise)
* @link https://book.cakephp.com.cn/2.0/en/core-libraries/components/access-control-lists.html#checking-permissions-the-acl-component
*/
public function check($aro, $aco, $action = "*") {
// if cache is disabled then default to normal operation
if(Configure::read('Cache.disable') == true){
return $this->Permission->check($aro, $aco, $action);
}
// read name of cache config for AclCache
$cacheConfig = Configure::read('CacheDbAclConfig');
// if not found then use default
if(!$cacheConfig){
$cacheConfig = 'default';
}
// check which portion of $aro to use for key
$cacheAro = Configure::read('CacheDbAclAro');
// if not set just serialze $aro
if(!$cacheAro){
$cacheKey = 'CacheDbAcl_'.md5(serialize($aro).$aco.$action);
}
// use custom portion of $aro
else{
$tmp = explode('.', $cacheAro);
$aroTmp = false;
foreach($tmp as $i){
if($aroTmp == false){
$aroTmp = $aro[$i];
}
else{
$aroTmp = $aroTmp[$i];
}
}
if(!isset($aroTmp) || empty($aroTmp)){
$cacheKey = 'CacheDbAcl_'.md5(serialize($aro).$aco.$action);
}
else{
$cacheKey = 'CacheDbAcl_'.md5(serialize($aroTmp).$aco.$action);
}
}
// check for cache key in cache
$check = Cache::read($cacheKey);
// if key exists then return value
if( $check !== false ){
return $check;
}
// check database and write to cache
else{
$check = $this->Permission->check($aro, $aco, $action);
Cache::write($cacheKey,$check,$cacheConfig);
}
return $check;
}
/**
* Allow $aro to have access to action $actions in $aco
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $actions Action (defaults to *)
* @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
* @return boolean Success
* @link https://book.cakephp.com.cn/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
*/
public function allow($aro, $aco, $actions = "*", $value = 1) {
return $this->Permission->allow($aro, $aco, $actions, $value);
}
/**
* Deny access for $aro to action $action in $aco
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @link https://book.cakephp.com.cn/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
*/
public function deny($aro, $aco, $action = "*") {
return $this->allow($aro, $aco, $action, -1);
}
/**
* Let access for $aro to action $action in $aco be inherited
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
*/
public function inherit($aro, $aco, $action = "*") {
return $this->allow($aro, $aco, $action, 0);
}
/**
* Allow $aro to have access to action $actions in $aco
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @see allow()
*/
public function grant($aro, $aco, $action = "*") {
return $this->allow($aro, $aco, $action);
}
/**
* Deny access for $aro to action $action in $aco
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @see deny()
*/
public function revoke($aro, $aco, $action = "*") {
return $this->deny($aro, $aco, $action);
}
/**
* Get an array of access-control links between the given Aro and Aco
*
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @return array Indexed array with: 'aro', 'aco' and 'link'
*/
public function getAclLink($aro, $aco) {
return $this->Permission->getAclLink($aro, $aco);
}
/**
* Get the keys used in an ACO
*
* @param array $keys Permission model info
* @return array ACO keys
*/
protected function _getAcoKeys($keys) {
return $this->Permission->getAcoKeys($keys);
}
}