Yet another implementation of CPhpAuthManager.

You are viewing revision #1 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version.

next (#2) »

  1. 1. Induct the component into the application.
  2. 2. Keep the auth.php empty or void.
  3. 3. Keep the roles inside the database.
  4. 4. Assign the user a unique id.
  5. 5. Construct the authorization hierarchy inside the controller.
  6. 6. Selectively assign roles to the user.
  7. 7. Declare the rules in accessRules.

In this wiki, I try to implement a simple authorization schema without putting much logic inside a file or into database table. We are constructing authorization hierarchy inside the controller. We are getting roles for the current user from database table and assigning the only roles to user that are declared in the particular controller. We have brought down the work of loading of auth data at main application level to controller level. This way we have pulverised the auth data for whole site into smaller units. Lastly we are going to look into couple of examples.

1. Induct the component into the application.

protected/config/main.php

'components'=>array(
		'authManager'=>array(
			'class'=>'CPhpAuthManager',
			),

2. Keep the auth.php empty or void.

By default if authorization file is not declared in main configuration file, CPhpAuthManager file will look for a file protected/data/auth.php. Now we have to either delete the file or keep an empty array inside it.

protected/data/auth.php

return array();

3. Keep the roles inside the database.

The important thing is to declare the roles for individual user and store them inside the database table. In simpler situations, we can store the roles inside the user table itself. For following examples, I have created a separate table called role and created some roles.

  • PostManagement:reader,author,editor,chiefEditor.
  • UserManagement:userManager.

4. Assign the user a unique id.

By making some changes in the UserIdentity file in components folder, we can assign a unique id for individual user. Now Yii::app()->user->id would fetch the unique id.

protected/components/UserIdentity.php

class UserIdentity extends CUserIdentity
{   
	private  $_id;
	public function authenticate()
	{
		$user=User::model()->findByAttributes(array('username'=>$this->username));
		if($user===null)
			$this->errorCode=self::ERROR_USERNAME_INVALID;
		elseif($user->password!==md5($this->password."yourpassword"))
			$this->errorCode=self::ERROR_PASSWORD_INVALID;
		else
		{	
			$this->errorCode=self::ERROR_NONE;
			$this->_id=$user->id;//Here we are assigning pk of user as user Id.
		}
		return !$this->errorCode;
	}
	
	public function getId()
	{
		return $this->_id;
	}
} 

5. Construct the authorization hierarchy inside the controller.

We are going to declare a method inside the PostContoller.php.

PostController::loadAuth()

protected function loadAuth()
	{
		$auth=Yii::app()->authManager;
		
		//We have finely ground the permissions to controll all the actions.
		$auth->createOperation('viewPostList','view the list of posts');
		$auth->createOperation('viewPost','view a post');
		$auth->createOperation('createPost','create a new post');
		$auth->createOperation('updatePost','update a post');
		$auth->createOperation('deletePost','delete a post');
		$auth->createOperation('managePost','admininister publications');

               /**We have created a role reader.
                * Reader can view the list of posts or view a single post.
                */ 
		$reader=$auth->createRole('reader');
		$reader->addChild('viewPostList');
		$reader->addChild('viewPost');
		
		/**We are going to create a role author. 
		 * Author can be a reader.
		 * Author can also create a post
		 * Author will get a task updateOwnPost.
		 * Through the task, author can only update his/her own post.
		 * For this purpose, we have assinged a rule for it.
		 */ 
		$bizRule='return Yii::app()->user->id==$params["post"]->author_id;';
		$task=$auth->createTask('updateOwnPost','update only posts created by user',$bizRule);
		$task->addChild('updatePost');

		$author=$auth->createRole('author');
		$author->addChild('createPost');
		$author->addChild('updateOwnPost');
		$author->addChild('reader');
        
        /**We have created another role editor.
         * Editor is a reader.
         * He can edit any post.
         * But he can not edit posts made by chiefEditor.
         * To achieve this we have created a task with a biz rule.
         */
        $bizRule='return (int)$params["post"]->author_id!==1;';  //1==admin
		$task=$auth->createTask('updateNotChiefEditorPost','update only posts created by authors',$bizRule);
        $task->addChild('updatePost');
        
		$editor=$auth->createRole('editor');
		$editor->addChild('updateNotChiefEditorPost');
		$editor->addChild('reader');
		
		//ChiefEditor has got all the rights.
		$chiefEditor=$auth->createRole('chiefEditor');
		$chiefEditor->addChild('reader');
		$chiefEditor->addChild('createPost');
		$chiefEditor->addChild('updatePost');
		$chiefEditor->addChild('deletePost');
		$chiefEditor->addChild('managePost');
		
		return $auth;
	}

6. Selectively assign roles to the user.

Now we are going to fetch all the roles for current user is having from the database. and going to assign the roles selectively.

PostController::assignRoles()

protected function assignRoles()
	{
		$roles=Yii::app()->db->createCommand()
			->select('role_name')
			->from('role')
			->where('user_id=:id',array(':id'=>Yii::app()->user->id))
			->queryColumn();
		
		$auth=$this->loadAuth();
		
		foreach($roles as $role)
		{	
			/*We are not going to assign all the roles.
			*Only roles pertinent to this controller are assigened.
			*/
			if($auth->getAuthItem($role)!==null)
				$auth->assign($role,Yii::app()->user->id);
		}
	}
	
//Now call this method inside PostController::init
public function init()
	{
		$this->assignRoles();	
	}

7. Declare the rules in accessRules.

Now we are going to infuse this authorization logic into CAccessController filter.

PostController::accessRules()

public function accessRules()
	{   
		/**We have some busines rules related to updating a paricular post.
		 * To put the paricular post inside the params, we need the pk value of that post.
		 * We can do the following to achieve that.
		 */
		$params=array();
		$id=Yii::app()->request->getParam('id');//Choose the GET/POST parameters appropriately and populate $params.
		if(isset($id))
			$params['post']=$this->loadModel($id);
			
		/**We assign only the basic operations for each rule here.
		 * CPhpAuthManager::checkAccess method will take care of parents(task,role)
		 * Also look into code of CAccessRule::isRoleMatched method.
		 */ 	
		
		return array(
			array('allow',  
				'actions'=>array('index'),
				'roles'=>array('viewPostList'),
			),
			array('allow',  
				'actions'=>array('view'),
				'roles'=>array('viewPost'),
			),
			array('allow', 
				'actions'=>array('create'),
				'roles'=>array('createPost'),
			),
			array('allow', 
				'actions'=>array('update'),
				'roles'=>array('updatePost'=>$params),
			),
			array('allow', 
				'actions'=>array('delete'),
				'roles'=>array('deletePost'),
			),
			array('allow', 
				'actions'=>array('admin'),
				'roles'=>array('managePost'),
			),
			array('deny', 
				'users'=>array('*'),
			),
		);
	}

Now in the same application, we are building authorization scheme for userManagement.

UserController.php

protected function loadAuth()
	{
		$auth=Yii::app()->authManager;
		
		/**Here we are declaring default roles.
		 * Default roles are assigned to all the users.
		 * It is going to work, if  assigned bizrules are met.
		 */ 
		$auth->defaultRoles=array('anonymous','authenticated');
		
		
		$auth->createOperation('listAccounts','view the list of all users');
		$auth->createOperation('viewAccount','view an user account');
		$auth->createOperation('register','register an account');
		$auth->createOperation('updateAccount','update an account');
		$auth->createOperation('deleteAccount','delete an user account');
		$auth->createOperation('manageAccount','admininister user accounts');
        
        /**Default role anonymous is created.
         * We are attaching a bizRule so that guests only can assume anonymous role.
         * They can only create an account.
         */ 
		$bizRule='return Yii::app()->user->isGuest;';
		$anonymous=$auth->createRole('anonymous','anonymous only can register',$bizRule);
		$anonymous->addChild('register');
		
		/**Default role authenticated is created.
		 * This has a child userAccount(task).
		 * The task ensures that user can view or update only his or her account.
		 */
		$bizRule='return Yii::app()->user->id==$params["user"]->id;';
		$task=$auth->createTask('userAccount','view or edit only own account',$bizRule);
		$task->addChild('viewAccount');
		$task->addChild('updateAccount');
		
		$authenticated=$auth->createRole('authenticated');
		$authenticated->addChild('userAccount');
		
		/**userManger role is declared in database.
		 * He has all the rights regarding user accounts.
		 */ 
		$manager=$auth->createRole('userManager');
		$manager->addChild('listAccounts');
		$manager->addChild('viewAccount');
		$manager->addChild('updateAccount');
		$manager->addChild('userAccount');
		$manager->addChild('deleteAccount');
		$manager->addChild('manageAccount');
		
		return $auth;
	}

public function accessRules()
	{   
		$params=array();
		$id=Yii::app()->request->getParam('id'); //Choose the GET/POST parameters appropriately and populate $params.
		if(isset($id))
			$params['user']=$this->loadModel($id);
		
                /* *The parent task userAccount has bizRule with it.	
                    *So we have to pass params with updateAccount and ViewAccount.
                    */
		return array(
			array('allow',  
				'actions'=>array('index'),
				'roles'=>array('listAccounts'),
			),
			array('allow',  
				'actions'=>array('view'),
				'roles'=>array('viewAccount'=>$params),
			),
			array('allow', 
				'actions'=>array('register'),
				'roles'=>array('register'),
			),
			array('allow', 
				'actions'=>array('update'),
				'roles'=>array('updateAccount'=>$params),
			),
			array('allow', 
				'actions'=>array('delete'),
				'roles'=>array('deleteAccount'),
			),
			array('allow', 
				'actions'=>array('admin'),
				'roles'=>array('manageAccount'),
			),
			array('deny', 
				'users'=>array('*'),
			),
		);
	}
/**You have to declare the method assignRoles here also .
*You have to call it  inside UserController::init() method.
*/

I really thank everyone going through this wiki. I would gracefully accept any criticism.

Thanking again!.