I have a few different levels of people that will be able to manage users. Is it possible to check if a user has a "higher" or same level of permission.
For instance, moderators shouldn’t be able to edit/manage admin level users admins shouldn’t be able to manage super admin. Ideally I don’t want to add a bunch of if-statements to check the user’s level against the user they’re attempting to manage.
Maybe permission of the level of users that role is allowed to manage?
I’m not sure I follow. Because access rules are attached to permissions, so then I’d need a permission/permissions hierarchy. So then I’d pass a user object of the current user and test that user’s role against the user the person is attempting to manage?
Can that be calculated, though? For instance if it used a numerical value or a bit I could check if the user that person is trying to manage has a higher level by just comparing those values.
current_user_role > other_user_role
The way I see it right now is that if I added additional roles, like a lower level moderator, I’d have to refactor the access rule every time.
If there’s a permission canManageUser then that can be set for moderators, canManageModerator for admins, canManageAdmin for super admins, but then if moderator is a parent of the user role, and subsequently admin is the parent of moderator and super admin is the parent of admin then admins would be able to edit super admin because super admin is also a user.
It seems paradoxical, but adding access rules to check above seems like it would require refactoring every time a new role is added. I’m not expecting roles to be added/removed regularly, but in the event that it does happen it seems that refactoring would be necessary. Or am I overlooking something, can you check if a role/permission is the parent of another role/permission?
Add ‘manageUsers’ permission as a child of ‘moderator’ role.
Add ‘moderator’ role and ‘manageModerators’ permission as children of ‘admin’ role.
Add ‘admin’ role and ‘manageAdmins’ permission as children of ‘superAdmin’ role.
Now you can check whether the current user has the right to manage a certain target user like the following:
public function canManageUser($user, $targetUser)
{
switch ($targetUser->kind) {
case 'normal' : $ret = $user->can('manageUsers'); break;
case 'moderator' : $ret = $user->can('manageModerators'); break;
case 'admin' : $ret = $user->can('manageAdmins'); break;
case 'superAdmin' : $ret = $user->can('manageSuperAdmins'); break;
default : $ret = false; break;
}
return $ret;
}
Note that you don’t need to (and should not) check the user’s role. You just have to check the specific permission for the action.
Sometimes you may need some refactoring because you may want to add some new role. Usually it can be done by adding a new permission, modifying the RBAC hierarchy, and adding some code to check the added permission.
So then I have this question about it. Why does RBAC not have relational foreign key constraints? For instance, auth_item_child has the parent and the child in text. While I understand this makes it easier to read it would be better if it relied on foreign key constraints from the auth_item table for performance and enforcing data integrity.
Which then the user table could easily reference the user’s “type” from the roles in the auth_item table. I don’t think user’s “type” should be independent. Even though the user’s table would have to be updated separately from the the RBAC tables, there’s no enforcement that the user’s “type” matches a role. The user could end up with the type “fish”, but “fish” isn’t a role. This would need to be programmatically enforced in PHP vs being enforced by database constraints.
yii\rbac\DbManager is extended from yii\rbac\BaseManager which also has yii\rbac\PhpManager as its child. While DbManager is meant for relatively large and complex RBAC, PhpManager is for small and simple one.
As you see in the description of DbManager::$cache, yii\rbac\DbManager is a kind of compromise. In other words, traditional db system is not the best vehicle for RBAC items and their relations, because they are not a 2 dimensional table but rather a network.