Yii Framework Forum: RBAC caching - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

RBAC caching Rate Topic: -----

#1 User is offline   sluderitz 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 105
  • Joined: 26-February 09
  • Location:Germany

Posted 27 August 2009 - 04:22 AM

I have started to use rbac implementing operations, tasks and roles.
For each controller-action pair I have an operation (i.e. user_create, user_delete, user_show, user_update).
To only show the buttons and menus people are allowed to use quite a lot of access checking is performed on every request. This results in up to 50 SQL queries per request, which I think is not acceptable.

My solution to this problem is to cache the access rights in the session:
Yii already provides access rights caching within the same request through the CWebUser method 'checkAccess()'
So I wrote my own user class MyCWebUser extending CWebUser, it only overrides checkAccess().
<?php
<?php
class MyCWebUser extends CWebUser {
    public function checkAccess($operation,$params=array(),$allowCaching=true) {
        if($allowCaching && !$this->getIsGuest() && isset(Yii::app()->session['access'][$operation])) {
            return Yii::app()->session['access'][$operation];
        }
        $checkAccess = Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
        if($allowCaching && !$this->getIsGuest()) {
            $access = isset(Yii::app()->session['access']) ? Yii::app()->session['access'] : array();
            $access[$operation] = $checkAccess;
            Yii::app()->session['access'] = $access;
        }
        return $checkAccess;
    }
}


In your config file you also need to set the new user class:
'components'=>array(
    ...    
    'user'=>array(
        'class'=>'MyCWebUser',
    ),
    ...
)


When using accessControl filters in the controller the access rights are now cached in the session. Manually checking for access rights also works just like before: Yii::app()->user->checkAccess('operation_name').


There is one disadvantage though: changes to the operations/tasks/roles structure or assignment of roles do not take effect until the user has logged out and then logged in again. In my project I can live with that.
To solve that problem as well access rights could be stored in the file cache for example using a key that contains the userId. When changing role assignment to a user you would then have to delete the cache entry for that user, when changing the operations/tasks/roles structure you would have to delete the cache entries for all users.

I hope these ideas can help somebody, good luck with rbac!
1

#2 User is offline   Anticon 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 25
  • Joined: 25-February 09
  • Location:Germany

Posted 28 August 2009 - 01:27 AM

This is very useful. Thanks. :)
0

#3 User is offline   horizons 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 120
  • Joined: 18-December 08

Posted 03 November 2009 - 05:45 AM

I have also the same issue with the rbac and high sql query count thanks for your solution to settle down the problem a bit.
0

#4 User is offline   Athos 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 90
  • Joined: 07-January 11

Posted 17 May 2011 - 07:11 AM

I made ​​some improvements to reduce the problem with the change of permission during the session.
I added a control that forces the revision of permission every 30 minutes.
And I also added the cache control by request of the original class.

class TWebUser extends RWebUser
{
	private $_access=array();
        
        public function checkAccess($operation,$params=array(),$allowCaching=true)
        {
                if($this->isSuperuser===true)
                        return true;                
                
		if($allowCaching && $params===array() && isset($this->_access[$operation]))
			return $this->_access[$operation];                
                
                $cache = Yii::app()->session['checkAccess'];
                if($allowCaching && !$this->getIsGuest() 
                    && isset($cache[$operation])
                    && time() - $cache[$operation]['t'] < 1800)
                {
                    $checkAccess = $cache[$operation]['p'];
                }
                else
                {                
                    $checkAccess = Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
                    
                    if($allowCaching && !$this->getIsGuest())
                    {
                        $access = isset($cache) ? $cache : array();
                        $access[$operation] = array('p'=>$checkAccess, 't'=>time());
                        Yii::app()->session['checkAccess'] = $access;
                    }
                }
                
                return $this->_access[$operation] = $checkAccess;
        }
}


I use Rights and my class extends the class of the extension.
Thanks Google Translator to helping me write the posts :)
1

#5 User is offline   nexus246 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 12
  • Joined: 02-December 09

Posted 08 June 2011 - 10:54 AM

It's important to know that above solution doesn't work when using bizrules (ex. checking content author by $_GET['id'])
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users