Role weights not working as expected
- Bobbles
- Member | 3
Hello all, firstly may I just say that I've been working with Nette for a week or so now, and I love how it works, so congratulations on a great Framework. The English documentation is a bit thin in places, and I can't seem to find a solution for the following issue.
I have assigned a test user two roles, “probationary”, and “troll”. The troll role should simply deny the user a few permissions. I'm aware of role weight, with the last added role having the greater weight. So I'm therefore stumped as to why my code doesn't work.
$acl->addRole('guest');
$acl->addRole('probationary');
$acl->addRole('admin');
$acl->addRole('troll');
$acl->addResource('articles');
$acl->addResource('links');
$acl->addResource('pages');
$acl->addResource('profiles');
$acl->allow('probationary', 'profiles', 'view');
$acl->deny('troll', 'profiles', 'view');
So from that code, I was expecting for the user not to be allowed to view profiles, but the following code returns true.
View Profiles {dump($user->isAllowed('profiles', 'view'))}
TRACY shows the user logged in as follows
Nette\Security\Identity #01
id private => 1
roles private => array (2)
0 => "probationary"
1 => "troll"
data private => array (3)
username => "test"
displayname => "My Display Name"
email => "test@test.com"
Everything works as expected when I just have one role assigned to the user. Any ideas as to what I'm doing wrong? Thanks in advance.
- Majkl578
- Moderator | 1364
I'm afraid you are slightly mixing two things here. Role weight (in the
context of ACL) only works together with role inheritance. ACL is then always
queried with a single role.
User class does this slightly differently – it doesn't work like inheritance,
the ACL is queried for each assigned role sequentially, in the same order they
were set in the Identity, and if any of them passes, user is granted the
access.
- Ages
- Member | 128
Here is basic implementation of static ACL:
config.neon
services:
authorizatorFactory: App\Components\AuthorizatorFactory
authorizator: @authorizatorFactory::create
AuthorizatorFactory.php
<?php
namespace App\Components;
use Nette\Security\Permission;
class AuthorizatorFactory
{
/**
* @return \Nette\Security\IAuthorizator
*/
public function create() {
$permission = new Permission();
/* User role definition */
$permission->addRole('guest'); //--- Anonymous user
$permission->addRole('customer'); //--- Signed user
$permission->addRole('admin'); //--- Admin
/* List of resources */
$permission->addResource('Admin'); //--- Admin
$permission->addResource('Homepage'); //--- Articles
$permission->addResource('Redactor'); //--- Redactor
$permission->addResource('Shop'); //--- E-shop
/* Permissions settings */
$permission->allow('guest', ['Homepage', 'Shop'], ['show']);
$permission->allow('customer', ['Homepage', 'Shop'], ['show', 'edit']);
$permission->allow('admin', Permission::ALL, Permission::ALL);
return $permission;
}
}
- Bobbles
- Member | 3
Hi Ages. Thanks for taking the time out for the code. However, that part
I understand and have something similar myself. My issue is more with multiple
roles for a user. I create a new Identity with two roles assigned (in my case
probationary and troll). I just want the troll role to take away some
permissions from the assigned probationary role, but the
$acl->deny(‘troll’, ‘profiles’, ‘view’); code has no effect in
the case of my original code above.
I gather from what Majkl578 said however, I'm missing a piece of the puzzle, and that's the part I don't understand.
- duke
- Member | 650
I am afraid with current
implementation of Nette\Security\User it is not possible to deny access to
some resources by adding a new role to the user. You can only achieve allowing
more access by doing this.
Hence the only way to restrict access is to remove some roles from
the user.