See an update here: Real-caching CakePHP permitted actions
In my previously posted CakePHP component/helper pair (and more) that displays links in views depending upon ACL permissions, I've added a fake caching system for storing permissions. I call it "fake" caching because I'm not using Cake's cache system at all. Rather, I'm "caching" the user's ACL-permitted actions in his session. Whenever the session is regenerated, the fake cache will be, also. It will also allow forcing of a refresh of the list. First up, here's the code that I drop into app_controller.php:
/**
* "Fake caching" of permitted controller/action pairs into the user's session.
*
* @param bool $refresh Set to true to force refresh of permitted controller/action pairs.
*/
function _sessioncachePerms($refresh = false)
{
//$refresh=true;
$uid = $this->Auth->user('id');
if ($refresh && $uid)
{
$this->Session->delete('Auth.AclPermsUser'.$uid);
}
$isCacheSet = $this->Session->read('Auth.AclPermsUser'.$uid);
if ($this->Auth && $this->Acl && $uid && empty($isCacheSet))
{
// group perms
$pArr = array();
$allPerms = $this->Acl->Aro->find('threaded', array('conditions' => array('Aro.foreign_key' => $this->Auth->user('group_id'))));
foreach ($allPerms[0]['Aco'] as $action)
{
$pArr[] = $this->Acl->Aco->getpath($action['id']);
}
$perms = array();
$permsCounter = 0;
foreach ($pArr as $permStruct)
{
$perms[$permsCounter] = '';
foreach ($permStruct as $permChunk)
{
$perms[$permsCounter] .= $permChunk['Aco']['alias'] .'/';
}
$perms[$permsCounter] = rtrim($perms[$permsCounter], '/');
if (!$this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('id')), $perms[$permsCounter]))
{
unset($perms[$permsCounter]);
}
$permsCounter++;
}
// $perms contains permitted ACOs, but not Auth->allowedActions
//debug($perms);
// user perms
$pArr = array();
//$allPerms = $this->Acl->Aro->find('threaded', array('conditions' => array('Aro.foreign_key' => $this->Auth->user('group_id'))));
//debug($allPerms);
foreach ($allPerms[0]['children'][0]['Aco'] as $action)
{
$pArr[] = $this->Acl->Aco->getpath($action['id']);
}
foreach ($pArr as $permStruct)
{
$perms[$permsCounter] = '';
foreach ($permStruct as $permChunk)
{
$perms[$permsCounter] .= $permChunk['Aco']['alias'] .'/';
}
$perms[$permsCounter] = rtrim($perms[$permsCounter], '/');
if (!$this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('id')), $perms[$permsCounter]))
{
unset($perms[$permsCounter]);
}
$permsCounter++;
}
// $perms contains permitted ACOs, but not Auth->allowedActions
//debug($perms);
$this->Session->write('Auth.AclPermsUser'.$uid, $perms);
}
}
And then I add
$this->_sessioncachePerms();in AppController's beforeFilter() after the Auth setup. The only other placed I've used it in the sandbox is after changing permissions on an ARO. Then it's necessary to use
$this->_sessioncachePerms(true);to force a rebuild of the "cache".
Instead of templatizing my previous work to permit operation with either constant ACL checks or this fake caching, I just changed the AclPermittedActions component to work only with this. I might get around to making a generic system in the future, but I don't have the need or the time right now. I'll attach the modified component to this post.
I should note that this arrangement will not work with a controller's Auth->allowedActions. That can be implemented, but it would require quite a bit of overhead on the initial cache build because it would require using something like a controller list and a series of App::import()s, I think. It's something that would be good to have, but the main app I'm working on will have permissions on every action set through ACL allow/deny rather than allowedActions. That wouldn't work so well for an open website, but it's necessary for this project.
| Attachment | Size |
|---|---|
| 4.63 KB |
Add new comment