Rights Alternative


(Thomasatmann) #1

Hi All…

I have an application I’m building and i installed the Rights Extension, which is great but makes about 40 db calls in one page load. the tables also don’t seem to follow normal design conventions. I’m worried that this may become and issue as the site grows…

I was looking at srbac but there is now UI demos so i don’t know how robust it is. What are your thoughts?? Should i be worried about Rights scalability? Does srbac have a better ui?? Rights is ok but its lacking in some areas.

is there another system out there?

Many Thanks.


(Jacob Moen) #2

I am quite fond of userGroups :)

It’s lean and combines user and rights management.

Rights is great, though. But too bulky for my needs.


(Nganhtuan63) #3

Hello, I’ve used rights and implements the caching for rights like this:

1/ Edit the AuthItemController.php to support generate Permission Cache File

Add new functions





	/**

	* Generate Permission into File

	*/

	public function actionGenerateFile(){

		

		// Delete old cache

		Yii::app()->cache->delete('permission-cache');			

		// Generate new cache				

		$rdb_auth_manager=new RDbAuthManager;		

		

		//Get all roles

		$sql = "SELECT name,t1.type,description,t1.bizrule,t1.data

				FROM {$rdb_auth_manager->itemTable} t1					

				WHERE t1.type=2

				ORDER BY t1.type DESC";

		$command=Yii::app()->db->createCommand($sql);		

		$roles=$command->queryAll();


		//Get all items

		$sql = "SELECT name,t1.type,description,t1.bizrule,t1.data

				FROM {$rdb_auth_manager->itemTable} t1					

				WHERE t1.type<>2

				ORDER BY t1.type DESC";

		$command=Yii::app()->db->createCommand($sql);

		$items=$command->queryAll();

								

		$permissions=array();

		//Create permission item array

		foreach($items as $item){

			

			$permissions[$item['name']]['bizrule']=$item['bizrule'];

			$permissions[$item['name']]['data']=$item['data'];				

			if(!isset($permissions[$item['name']]['roles']))			

				$permissions[$item['name']]['roles']=array();			

			if(!isset($permissions[$item['name']]['users']))			

				$permissions[$item['name']]['users']=array();

						

			

			// Check if there is any user assigned with this item

			$sql = "SELECT userid,bizrule,data

				FROM {$rdb_auth_manager->assignmentTable}

				WHERE itemname=:name";

			$command=Yii::app()->db->createCommand($sql);

			$command->bindParam(":name",$item['name'],PDO::PARAM_STR);


			$a_users=$command->queryAll();

			if($a_users && count($a_users)>0){

					foreach($a_users as $a_user){

						$permissions[$item['name']]['users'][$a_user['userid']]['bizrule']=$a_user['bizrule'];

						$permissions[$item['name']]['users'][$a_user['userid']]['data']=$a_user['data'];


						// Get child Items of current items 

						// to make sure if the user is assigned to parent item,

						// it must be assigned to all children items of this parent

						$child_items=$this->getChildItemsRecursive($item['name']);

						if($child_items and count($child_items)>0){

							foreach($child_items as $key=>$value){

								$permissions[$key]['bizrule']=$value['bizrule'];

								$permissions[$key]['data']=$value['data'];


								if(!isset($permissions[$key]['roles']))			

									$permissions[$key]['roles']=array();			


								if(!isset($permissions[$key]['users']))			

									$permissions[$key]['users']=array();


								// Assign user to Item,

								$permissions[$key]['users'][$a_user['userid']]['bizrule']=null;

								$permissions[$key]['users'][$a_user['userid']]['data']="N;";

							}

						}

					}

			}		

			

			// Check roles that are allowed with this item				

			$permissions[$item['name']]['roles']=$this->getAllowedRolesRecursive($item['name']);

			//$permissions[$item['name']]['users']=array_unique($permissions[$item['name']]['users']);

			$permissions[$item['name']]['roles']=array_unique($permissions[$item['name']]['roles']);

		}

		

		

		Yii::app()->cache->set('permission-cache',$permissions,0); // No expire


		Yii::app()->user->setFlash($this->module->flashSuccessKey,

    		Rights::t('core', 'Updated Permission Cache')

    	);

    	Yii::app()->controller->redirect(array('authItem/permissions'));  		

	}


	public  function getChildItemsRecursive($itemname){		

		$items=array();

		$rdb_auth_manager=new RDbAuthManager;		

		$sql = "SELECT t2.type,t2.name,t2.bizrule,t2.data

			FROM {$rdb_auth_manager->itemChildTable} t1

			INNER JOIN {$rdb_auth_manager->itemTable} t2 ON t1.child=t2.name

			WHERE t2.type<>2 AND parent=:name";

		$command=Yii::app()->db->createCommand($sql);

		$command->bindParam(":name",$itemname,PDO::PARAM_STR);

		

		$childrens=$command->queryAll();

		if(!($childrens && count($childrens)>0)){							

			return $items;

		} else {

			foreach($childrens as $child){

				$items[$child['name']]['bizrule']=$child['bizrule'];

				$items[$child['name']]['data']=$child['data'];

				$temp_items=$this->getChildItemsRecursive($child['name']);

				$items=array_merge($items,$temp_items);	

			}

			return $items;

		}

	}


	public  function getAllowedRolesRecursive($itemname){		

		

		$rdb_auth_manager=new RDbAuthManager;		

		// Check roles that are allowed with this item				

		// Get parent of the item

		$roles=array();

		$sql = "SELECT t2.type,t2.name

			FROM {$rdb_auth_manager->itemChildTable} t1

			INNER JOIN {$rdb_auth_manager->itemTable} t2 ON t1.parent=t2.name

			WHERE child=:name";

		$command=Yii::app()->db->createCommand($sql);

		$command->bindParam(":name",$itemname,PDO::PARAM_STR);

		$parents=$command->queryAll();

				

		if(!($parents && count($parents)>0)){							

			return $roles;

		} else{

			foreach($parents as $p){

				if($p['type']==2){									

					$roles[]=$p['name'];

				}		

				$temp_roles=$this->getAllowedRolesRecursive($p['name']);

				$roles=array_merge($roles,$temp_roles);								

			}	

			return array_merge($roles,$temp_roles);								

		}

		

	}




Add generateFile to accessRules




/**

	 * Specifies the access control rules.

	 * This method is used by the 'accessControl' filter.

	 * @return array access control rules

	 */

	public function accessRules()

	{

		return array(

			array('allow', // Allow superusers to access Rights

				'actions'=>array(

					'permissions',

					'operations',

					'tasks',

					'roles',

					'generate',

					'create',

					'update',

					'delete',

					'removeChild',

					'assign',

					'revoke',

					'sortable',

					'generateFile'

				),

				'users'=>$this->_authorizer->getSuperusers(),

			),

			array('deny', // Deny all users

				'users'=>array('*'),

			),

		);

	}




2/ Add getArrayRoles in Rights.php




/**

     * Static Function retrun Array Roles of the User

     * @param bigint $uid

     * @return string

     */

	public static function getArrayRoles($uid=0)

	{

			$res=array();

			if($uid){

				$roles=Rights::getAssignedRoles($uid,true);

		        $res=array();

				foreach($roles as $r){

					$res[]=$r->name;

				}		                		

			} 			

			return $res;

		

	}



3/ Edit RWebUser.php file

Add user roles state after user logged in




/**

	* Actions to be taken after logging in.

	* Overloads the parent method in order to mark superusers.

	* @param boolean $fromCookie whether the login is based on cookie.

	*/

	public function afterLogin($fromCookie)

	{

		parent::afterLogin($fromCookie);


		// Set User Roles here

        $this->setState('current_roles', Rights::getArrayRoles($this->getId()));

        

		// Mark the user as a superuser if necessary.

		if( Rights::getAuthorizer()->isSuperuser($this->getId())===true )

			$this->isSuperuser = true;

	}



Add new functioncs




public function checkAccessWithCache($operation, $params=array(), $allowCaching=true){

            

            $permissions=Yii::app()->cache->get('permission-cache');                                 

            if($permissions!==false){                

                if(!array_key_exists($operation,$permissions)){

                    return false;

                }                

                if($this->executeBizRule($permissions[$operation]['bizrule'],$params,$permissions[$operation]['data']))

                {


                    //Check with default Roles

                    if(in_array(app()->authManager->defaultRoles, $permissions[$operation]['roles'])){

                        return true;

                    }

                    //Check if allow user id for current operation                

                    if(array_key_exists($this->getId(), $permissions[$operation]['users'])){                    

                        $uid=$this->getId();

                        if($this->executeBizRule($permissions[$operation]['users'][$uid]['bizrule'],$params,$permissions[$operation]['users'][$uid]['data']))

                            return true;

                    }           

                    //Check if allow user id for current operation  

                    $check_roles = array_intersect($this->getState('current_roles'),$permissions[$operation]['roles']);                   

                    return count($check_roles)>0;

                    

                }

            } else {

                parent::checkAccess($operation, $params, $allowCaching);    

            }

            

        }


        public function executeBizRule($bizRule,$params,$data) 

        { 

            return $bizRule==='' || $bizRule===null || ($this->showErrors ? eval($bizRule)!=0 : @eval($bizRule)!=0); 

        }



Ask checkAccess function to use the new function we defined




/**

        * Performs access check for this user.

        * Overloads the parent method in order to allow superusers access implicitly.

        * @param string $operation the name of the operation that need access check.

        * @param array $params name-value pairs that would be passed to business rules associated

        * with the tasks and roles assigned to the user.

        * @param boolean $allowCaching whether to allow caching the result of access checki.

        * This parameter has been available since version 1.0.5. When this parameter

        * is true (default), if the access check of an operation was performed before,

        * its result will be directly returned when calling this method to check the same operation.

        * If this parameter is false, this method will always call {@link CAuthManager::checkAccess}

        * to obtain the up-to-date access result. Note that this caching is effective

        * only within the same request.

        * @return boolean whether the operations can be performed by this user.

        */

        public function checkAccess($operation, $params=array(), $allowCaching=true)

        {               


            return $this->isSuperuser===true ? true : $this->checkAccessWithCache($operation, $params, $allowCaching);                         

        }



4/ Edit layout to add Generate File Cache button




<?php $this->beginContent(Rights::module()->appLayout); ?>


<div id="rights" class="container">


	<div id="content">


		<?php if( $this->id!=='install' ): ?>

                       <?php Yii::app()->controller->menu= array(

                                    array(

                                            'label'=>Rights::t('core', 'Assignments'),

                                            'url'=>array('assignment/view'),

                                            'itemOptions'=>array('class'=>'item-assignments'),

                                            'linkOptions'=>array('class'=>'button'),

                                    ),

                                    array(

                                            'label'=>Rights::t('core', 'Permissions'),

                                            'url'=>array('authItem/permissions'),

                                            'itemOptions'=>array('class'=>'item-permissions'),

                                            'linkOptions'=>array('class'=>'button'),

                                    ),

                                    array(

                                            'label'=>Rights::t('core', 'Roles'),

                                            'url'=>array('authItem/roles'),

                                            'itemOptions'=>array('class'=>'item-roles'),

                                            'linkOptions'=>array('class'=>'button'),

                                    ),

                                    array(

                                            'label'=>Rights::t('core', 'Tasks'),

                                            'url'=>array('authItem/tasks'),

                                            'itemOptions'=>array('class'=>'item-tasks'),

                                            'linkOptions'=>array('class'=>'button'),

                                    ),

                                    array(

                                            'label'=>Rights::t('core', 'Operations'),

                                            'url'=>array('authItem/operations'),

                                            'itemOptions'=>array('class'=>'item-operations'),

                                            'linkOptions'=>array('class'=>'button'),

                                    ),

                                    array(

                                        'label'=>Rights::t('core', 'Update Permission Cache File'),

                                        'url'=>array('authItem/generateFile'),

                                        'itemOptions'=>array('class'=>'item-operations'),

                                        'linkOptions'=>array('class'=>'button'),

                                    ),

                            ); 

                       ?>

			


		<?php endif; ?>


		<?php $this->renderPartial('/_flash'); ?>


		<?php echo $content; ?>


	</div><!-- content -->


</div>


<?php $this->endContent(); ?>



Maybe there are still some bugs but it worked for me so far. Hope this helps.

P/s: When edit permissions with Rights, remember to run generateFile to re-generate new Cache File


(Ricobregon) #4

If you speak some spanish, Cruge is an excellent alternative. (English translation is currently in progress)