Hi there,
I’m using YII 2.0’s advanced template and having hard time making my RBAC to work.
I have three roles, in ascending order of powers: agent, staff, admin.
Only staff and admin can login at my backend (access gets managed through RBAC and it works fine).
Once logged in, admin can edit any user, while staff members should only be able to edit agents and their own profile. Here I’m tragically failing… (tragedy comes from how many times I’ve re-re-re-read The Guide and a ton of pages about RBAC).
I’ve built two rules, once to check if a user (staff member) is editing his/her own profile, the second to check if a staff member is trying to edit an agent. In logs, I see both rules executed, but the outcome is not as expected.
So, this is my self check rule:
namespace backend\rbac;
use Yii;
use yii\rbac\Rule;
/**
* Checks if userID matches user passed via params
*/
class SelfcheckRule extends Rule
{
public $name = 'selfcheck';
/**
* @param string|int $user the user ID.
* @param Item $item the role or permission that this rule is associated with
* @param array $params parameters passed to ManagerInterface::checkAccess().
* @return bool a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
/return check if current user is the same going to be edited
return Yii::$app->user->id == $user;
}
}
And this is the staff vs. agent editing rule:
namespace backend\rbac;
use Yii;
use yii\rbac\Rule;
/**
* Checks if userID matches user passed via params
*/
class AgentcheckRule extends Rule
{
public $name = 'agentcheck';
/**
* @param string|int $user the user ID.
* @param Item $item the role or permission that this rule is associated with
* @param array $params parameters passed to ManagerInterface::checkAccess().
* @return bool a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
// requestor is a Staff member
$isRequestorStaff = Yii::$app->authManager-> getAssignment('staff', Yii::$app->user->id) != null;
// target user is an Agent
$isTargetAgent = Yii::$app->authManager-> getAssignment('agent', $user) != null;
return $isRequestorStaff && $isTargetAgent;
}
}
In my RBAC controller I set up auth as follows:
...
...
// add "editUser" permission
$editUser = $auth->createPermission('editUser');
$editUser->description = 'Edit Users';
$auth->add($editUser);
// add self check rule
$selfrule = new SelfcheckRule;
$auth->add($selfrule);
$editSelf = $auth->createPermission('editSelf');
$editSelf->description = 'Update own profile';
$editSelf->ruleName = $selfrule->name;
$auth->add($editSelf);
// add role rule
$agentrule = new AgentcheckRule;
$auth->add($agentrule);
$editAgent = $auth->createPermission('editAgent');
$editAgent->description = 'Update agent profiles';
$editAgent->ruleName = $selfrule->name;
$auth->add($editAgent);
// add "staff" role and give this role above permissions
$staff = $auth->createRole('staff');
$auth->add($staff);
// allow "staff" to update their own and agent profiles
$auth->addChild($staff, $editSelf);
// "editSelf" will be used when "editAgent" fails
$auth->addChild($editSelf, $editAgent);
// "editAgent" will be used when "editUser" fails
$auth->addChild($editAgent, $editUser);
// add "admin" role and give this role all remaining permissions
$admin = $auth->createRole('admin');
$auth->addChild($admin, $editUser);
$auth->addChild($admin, $staff);
Finally, in my UserController, my understanding is that I just need to set up behaviors like this to make things work, without need to check again permissions in actions’ code:
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => \yii\filters\AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['index', 'view'],
// loginBackend permission only allows staff and admin to log into from backend
'roles' => ['loginBackend']
],
[
'allow' => true,
'actions' => ['update'],
// admin only has this permission, staff members should go through selfcheck/editAgent rules
'roles' => ['editUser']
],
[
'allow' => true,
'actions' => ['create', 'delete'],
// admin only has this permission
'roles' => ['createUser']
],
[
'allow' => false
]
]
]
];
}
With this setup, admin gets the right powers (can edit every user) but staff members get those powers too! As I said, in logs I see both rules checked, so I suspect something is wrong in there, like both rules always return true.
Does anybody have an idea about what am I doing wrong?
Edit::
Ok, my rules are definitely wrong: my understandings were wrong (I was considering rules’ $user argument wrong). I’ve realized I miss the id of the user model I’m going to edit, when I’m in rules. But how do I pass it to my rule?
Well, I could check for permissions in my UserController’s Update action, like the example in The Guide shows:
if (\Yii::$app->user->can('updateUser', ['user' => $user])) {
// update user
}
But then The Guide says:
So now my question is: how do I pass arguments to my rules, using AccessControl?
TIA,
rash*