Yii::app()->user->checkAccess() does not work

In chapter 8, when instructed to add something like this into project’s view.php




$curuser= Yii::app()->user->getId();

if(Yii::app()->user->checkAccess('createUser',$curuser))

{

	$this->menu[] = array('label'=>'Add user to project', 'url'=>array('adduser', 'id'=>$model->id));

}



It does not work, running var_dump on $curuser returns "false", even when the project listing shows Create user as that of what I am logged in with.

I am confused where the "createUser" should get its value as well… Is it from "AuthAssignment" or maybe from "tbl_project", or maybe some other table?

I might be horribly wrong as I’ve not read the book, but it makes sense to me that you don’t need to give the id of the user in the checkAcces() method as you’re executing it from within the Yii::app()->user.

Have you tried?




if(Yii::app()->user->checkAccess('createUser'))



Are you referring to the top of page 212? If so, this code does not send in the id of the user as the second parameter, it sends in the project model AR object instance.

the second parameter passed in is:


array('project'=>$model)

Sorry, you are correct. However it is still not working, I was probably just testing different methods and forgot about the original parameter.

running var_dump() on Yii::app()->user->checkAccess(‘createUser’,array(‘project’=>$model)) returns false, while the project details page reports the “Create User” same as I am logged in with.

I am using v1.1.6

The ‘createUser’ parameter is not a user name, it is the name of an authorization item, which is an entry in the AuthItem table. In this case, in order for this to return true, you will need to be logged in as a user who is assigned to the role “owner” in the AuthAssignment table. So, for example, if you are logged in as user ‘Crixus’ whose user_id is 5, then first of all there will need to be a row in the AuthAssignment table with

itemname: owner

userid: 5

This makes the assignment of the role, "owner" to this user. But since we have our roles defined in the context of specific projects, you will also need to ensure that you are an "owner" of the project you are looking at. This is what the bizrule does. It calls an extra method to see if you are, indeed, an owner of that project. This is the isUserInRole() method in the Project AR class. This checks the table tbl_project_user_role to see if the user is indeed in the role for a specific project. So, if you are looking at project_id = 2, then you would need the following row in this table

project_id: 2

user_id: 5

role: owner

And finally, the reason that the role of "owner" has the permission of "createUser" is due to the mapping in the table AuthItemChild. If you look at that table, you should find a row that establishes the item "createUser" as a child of "owner"

parent: owner

child: createUser

So, in the end, the authorization check

Yii::app()->user->checkAccess(‘createUser’,array(‘project’=>$model))

Is asking the following question:

“Is the current logged in user assigned the authorization permission item ‘createUser’?”

It does a recursive check against the AuthAssignment table to see if ‘creatUser’ or any of its parents are assigned to the user.

If so, then is will see if there is a bizrule defined in this assignment and execute it, and then return the true or false value returned from executing the bizrule.

I just finished the chapter 8 and although quite happy with the overall results, I am a bit uneasy, I sense that I skipped something or that there is a missing part of the whole RBAC equation that I haven’t got yet.

Back to the sample, It seem to me that a default project ‘owner’ assignment should happen automatically on project creation.

And that seems fairly simple to tackle by tapping in the CActiveRecord afterSave() callback and replicating what we did in createUser [guess that code should be in one place only, but for brevity I’m including here].

So I attempted to correct the issue by adding to the project.php model




	/**

	* Adds creator of the project as user and designate as default 'owner'

	*/

	protected function afterSave() {    

		$user = Yii::app()->user;

		$this->associateUserToProject($user->id); 

		$this->associateUserToRole('owner',$user->id);        

		$auth = Yii::app()->AuthManager;   

		if ($auth->getAuthAssignment('owner',$user->id) === null) {

			$bizRule = 'return isset($params["project"]) && $params["project"]->isUserInRole("owner");';

			$auth->assign('owner', $user->id, $bizRule);

		}

	}    



Which solves the problem but uncovered another issue of the "bizrule" being associated in the AuthAssignment with a "role, user_id" pair that will create duplicates in the original verify() function of the ProjectUserForm (easy fixed with the getAuthAssignment check shown above).

My doubt now, is that: although the above changes seem to have solved the assignment within the project context, not sure how the general authorization scheme should work. And I mean, how can I allow/restrict a given user to/for "Create Projects" in the first place.

I’ll aprecciate your comments,

Sergio

'Be kind whenever possible. It is always possible" - 14th DL

[SOLUTION]

I followed all of the advice in this thread, however checkAccess() was still returning false. I had a typo in the validate bizrule. I found it by comparing the code from inside MySQL server to what was submitted via the ProjectUserForm.verify method. I am reproducing my screens below, in case someone else finds it useful.

I am calling it from views/project/view/php like this:




if(Yii::app()->user->checkAccess('createUser',array('project'=>$model)))

{

	$this->menu[]=array('label'=>'Add User to Project', 'url'=>array('adduser','id'=>$model->id));

}



I am logging in to the application as user: Test_User_Four

using this URL:

localhost/trackstar/index.php?r=project/view&id=2

Here is my tbl_user table:

here is my authassignment table:

this is from authItem table

this is from authitemchild

this is from tbl_project_user_role

It looks to me like Test_User_Four is the owner of project 2 and should be able to have access to createUser and see the link

here is my verify() function in ProjectUserForm.php which sets the bizRule




public function verify($atrribute, $params)

	{

		//Review LoginForm.authenticate() for further example.

		

		//only verify if no other input errors present

		if(!$this->hasErrors())

		{

			$user=User::model()->findByAttributes(array('username'=>$this->username));

			if($this->project->isUserInProject($user))

			{

				$this->addError('username', 'This user has already been added to the project.');

				

			}

			else

			{

				$this->project->associateUserToProject($user);

				$this->project->associateUserToRole($this->role, $user->id);

				$auth=Yii::app()->authManager;

				$bizRule='return isset($params["project"]) && params["project"]->isUserInRole("'.$this->role.'");';

				$auth->assign($this->role,$user->id,$bizRule);

				

			}

		}

	}



HERE’s THE PROBLEM





$bizRule='return isset($params["project"]) && params["project"]->isUserInRole("'.$this->role.'");';


//params missing a variable identifier $

//should be:


$bizRule='return isset($params["project"]) && $params["project"]->isUserInRole("'.$this->role.'");';




finally, here is the isUserInRole($role) function from the model Project.php




public function isUserinRole($role)

	{

		$sql = "SELECT role FROM tbl_project_user_role WHERE project_id=:projectId AND user_id=:userId AND role=:role";

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

		$command->bindValue(":projectId", $this->id, PDO::PARAM_INT);

		$command->bindValue(":userId", Yii::app()->user->getId(), PDO::PARAM_INT);

		$command->bindValue(":role", $role, PDO::PARAM_STR);

		

		return (($command->execute()==1) ? true : false);

	}



[s]Any idea of what I may be doing wrong or what else I can try to make this work?

[/s]If you go to your database and inspect the value in the ‘bizrule’ field in authassignment table you can see the typo more easily:




// this is bad

return isset($params["project"]) && params["project"]->isUserInRole("owner");


//this is good

return isset($params["project"]) && $params["project"]->isUserInRole("owner");




HTH

Nice work, windsor for spotting that missing $. You have saved us a lot of money for aspirins :D

hi all,

i thing i had the same problem and couldn’t found new link in menu ( [add user to project] ).

now is ok because I insert manually in AuthAssignment one record after read this topic.


insert into AuthAssignment(itemname, userid) values('owner',3)

i’m on site 210 and still wondering how i could miss text about creating this line in this table.

can someone tell me where in book is paragraph about that? :)

maybe the reason is different?

thx :)

Right ! Thanks windsor to point out that prob. Mine was the same, i made a typo in the $bizRule

And more critical i did not made that typo in the unit test so everything seems ok ! I’ll now make a copy/paste of that bizRule !

models/ProjectUserForm.php

I had to add:


 64                 $this->project->associateUserToProject($user);

 65                 $this->project->associateUserToRole($this->role,$user->id);

 66                 $auth = Yii::app()->authManager;

 67                 $bizRule='return isset($params["project"]) && $params["project"]->isUserInRole("'.$this->role.'");';

 68                 $auth->assign($this->role,$user->id, $bizRule);

 69               $auth->save();

Added:


$auth->save();

$bizRule wasn’t saving.

USERiDENTITY.PHP


public function authenticate()

    {

        $record = RRegister::model()->findByAttributes(array('username'=>$this->username));

        if($record===null)

            $this->errorCode=self::ERROR_USERNAME_INVALID;

        

        else if($record->password!==$this->password)

            $this->errorCode=self::ERROR_PASSWORD_INVALID;

        else

        {

            $this->id=$record->id;

            echo $this->setState('role', $record->role); 

            

            $this->errorCode=self::ERROR_NONE;

        }

        return !$this->errorCode;

    }

 

    public function getId(){

        return $this->id;

    }



MAIN.PHP





'user'=>array(

			// enable cookie-based authentication

			'allowAutoLogin'=>true,

                    //set user role class

                   'class' => 'WebUser',

		),



components/webuser.php




<?php


/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

class WebUser extends CWebUser

{

    /**

     * Overrides a Yii method that is used for roles in controllers (accessRules).

     *

     * @param string $operation Name of the operation required (here, a role).

     * @param mixed $params (opt) Parameters for this operation, usually the object to access.

     * @return bool Permission granted?

     */

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

    {

        if (empty($this->id)) {

            // Not identified => no rights

            return false;

        }

       $role = $this->getState("role");

        if ($role === 'admin') {

            return true; // admin role has access to everything

        }

        // allow access if the operation request is the current user's role

        return ($operation === $role);

    }

}

?>



VIEW FORM:




<div id="mainmenu">

		<?php 

                $user = Yii::app()->user;

                $this->widget('zii.widgets.CMenu',array(

			'items'=>array(

				array('label'=>'Home', 'url'=>array('/site/index')),

				//array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),

				//array('label'=>'Contact', 'url'=>array('/site/contact')),

                                array('label'=>'Create Account', 'url'=>array('/RRegister/create'),'visible'=>$user->checkAccess('admin')),

                                array('label'=>'Amount Deposit', 'url'=>array('/RDEposit/create'),'visible'=>$user->checkAccess('staff')),

                                array('label'=>'Amount Transaction', 'url'=>array('/RTransaction/create'),'visible'=>$user->checkAccess('staff')),

                                array('label'=>'Amount Withdraw', 'url'=>array('/RWithdraw/create'),'visible'=>$user->checkAccess('normal')),

				array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),

				array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)

			),

		)); ?>

	</div><!-- mainmenu -->



this code is very useful for authenticate users…

thanks for this suggation

Hi ! good noon…

I have to know how to add rows dynamically using jquery .give ur sugesstion

Sir, I think we can pass id as a secund argument http://www.yiiframework.com/doc/api/1.1/CWebUser#checkAccess-detail