I have a simple ACL configures in an acl.global.php
like this:
return [
'acl' => [
'roles' => [
'guest' => null,
'member' => 'guest',
'admin' => 'member'
],
'resources' => [
'allow' => [
'Application\Controller\Index' => ['all' => 'member'],
'Application\Controller\Error' => ['all' => 'member'],
'Item\Controller\Process' => [
'index' => 'member',
'create' => 'member',
'showItem' => 'member', // website.tld/item/:id
'showList' => 'member' // website.tld/list-items
]
]
],
]
];
A parser iterates through the configuration and generates from the array elements calls to Zend\Permissions\Acl#allow(...)
like $this->allow($role, $controller, $action);
.
Now I need additionally to restrict the access of the users to the item's single view (mydomain.tld/item/:id
). A user should only get the access, if its id
equals to the item.user_id
(means: the user is the author/owner).
The way I see to implement this requirement is to extend the config
'Item\Controller\Process' => [
'index' => 'member',
'create' => 'member',
'showItem' => [
'role' => 'member',
'assertion' => 'UserIsOwner'
]
'showList' => 'member'
]
and to inject the Assertion
to Zend\Permissions\Acl#allow(...)
: $this->allow($role, $controller, $action, $assertion);
.
namespace Authorization\Acl\Assertion;
use ...
class UserIsOwner implements AssertionInterface
{
protected $userId;
// To inject the $userId can be the job of the factory.
public function __construct(int $userId)
{
$this->userId = $userId;
}
public function assert(Acl $acl, RoleInterface $role = null, ResourceInterface $resource = null, $privilege = null)
{
return return $this->userId === ???;
}
}
But now I have no idea, how the assertion should get the item.user_id
injected. The example in the docu doesn't have this problem, since it assets against the $_SERVER['REMOTE_ADDR']
.
I can inject the ItemService
to find out the item.user_id
:
public function assert(Acl $acl, RoleInterface $role = null, ResourceInterface $resource = null, $privilege = null)
{
return $this->isUserOwner();
}
protected function isUserOwner()
{
$itemId = ???;
$item = $this->itemService->findOne($itemId);
$itemOwnerId = $item->getUser()->getId();
return $this->userId == $itemOwnerId;
}
Though then I still need external data -- the current item.id
.
At what place can/should the variable item's data (in this case the item.user_id
or item.id
) be injected to an assertion?