如何建立在Zend框架2的变量值的ACL断言? [英] How to build an ACL Assertion for a variable value in Zend Framework 2?
问题描述
我有一个简单的ACL在配置 acl.global.php
是这样的:
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
]
]
],
]
];
通过配置解析器迭代,并从数组元素生成调用的 的Zend \\权限\\#的Acl允许(...)
像 $这个 - >允许($角色,$控制器,$行动);
现在我需要再限制用户对项目的单一视图访问( mydomain.tld /项目/:ID
)。用户应该只得到访问,如果它的 ID
等于给 item.user_id
(意思是:用户是作者/所有者)。
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'
]
和注入<一个href=\"https://github.com/zendframework/zend-permissions-acl/blob/master/src/Assertion/AssertionInterface.php\"相对=nofollow> 断言
来的 的Zend \\权限\\#的Acl允许(...)
: $这个 - &GT;允许($角色,$控制器,$行动,$断言);
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 === ???;
}
}
但现在我不知道,断言如何获得 item.user_id
注射。在这个例子<一个href=\"http://framework.zend.com/manual/current/en/modules/zend.permissions.acl.advanced.html#writing-conditional-acl-rules-with-assertions\"相对=nofollow>实况没有这个问题,因为它的资产对 $ _ SERVER ['REMOTE_ADDR']
。
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']
.
我可以注入 ItemService
来找出 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;
}
虽然那时我还需要外部数据 - 目前的 item.id
在什么地方都可以/应变量项目的数据(在这种情况下, item.user_id
或 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?
推荐答案
最后,我通过通过资源
注射可变数据解决了这个问题。不要以为,这是最干净的或推荐的解决方案。反正它的工作原理。但它会很高兴知道,如何解决它清洁/更优雅的方式。
Finally I resolved the problem by injecting the variable data via the resource
. Don't think, that it's the cleanest or a recommended solution. Anyway it works. But it would be nice to know, how to resolve it a clean / more elegant way.
UserIsOwner
UserIsOwner
namespace Authorization\Acl\Assertion;
use Zend\Permissions\Acl\Assertion\AssertionInterface;
use Zend\Permissions\Acl\Acl;
use Zend\Permissions\Acl\Role\RoleInterface;
use Zend\Permissions\Acl\Resource\ResourceInterface;
use Item\Service\ItemService;
class UserIsOwner implements AssertionInterface
{
/**
*
* @var integer
*/
protected $userId;
/**
*
* @var ItemService
*/
protected $itemService;
public function __construct(int $userId, ItemService $itemService)
{
$this->userId = $userId;
$this->itemService = $itemService;
}
public function assert(Acl $acl, RoleInterface $role = null, ResourceInterface $resource = null, $privilege = null)
{
return isset($resource->getParams()['id']) ? $this->isUserOwner($resource->getParams()['id']) : false;
}
protected function isUserOwner($itemId)
{
$item = $this->itemService->findOne($itemId);
$itemOwnerId = $item->getUser()->getId();
return $this->userId == $itemOwnerId;
}
}
UserIsOwnerFactory
UserIsOwnerFactory
namespace Authorization\Acl\Assertion\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Authorization\Acl\Assertion\UserIsOwner;
class UserIsOwnerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$itemFieldsetService = $serviceLocator->get('Item\Service\ItemService');
$authenticationService = $serviceLocator->get('AuthenticationService');
$userId = !empty($authenticationService->getIdentity()['id']) ? $authenticationService->getIdentity()['id'] : null;
$service = new UserIsOwner($userId, $itemFieldsetService);
return $service;
}
}
ParametrizedResource
ParametrizedResource
namespace Authorization\Acl\Resource;
use Zend\Permissions\Acl\Resource\GenericResource;
use Zend\Mvc\Router\Http\RouteMatch;
class ParametrizedResource extends GenericResource
{
/**
* @var array Params. Here the RouteMatch#params.
* @see RouteMatch
*/
protected $params;
public function __construct($resourceId, array $params = [])
{
parent::__construct($resourceId);
$this->setParams($params);
}
/**
*
* @return the $params
*/
public function getParams()
{
return $this->params;
}
/**
*
* @param multitype: $params
*/
public function setParams($params)
{
$this->params = $params;
}
}
ACL
Acl
...
// @todo refactor
protected function addResources(array $resources)
{
foreach ($resources as $permission => $controllers) {
foreach ($controllers as $controller => $actions) {
if ($controller == 'all') {
$controller = null;
} else {
if (! $this->hasResource($controller)) {
$this->addResource(new Resource($controller, $this->routeMatchParams));
}
}
foreach ($actions as $action => $roleConfig) {
if (is_array($roleConfig)) {
foreach ($roleConfig as $role => $assertion) {
if ($action == 'all') {
$action = null;
}
$assertion = !empty($this->assertions[$assertion]) ? $this->assertions[$assertion] : null;
if ($permission == 'allow') {
$this->allow($role, $controller, $action, $assertion);
} elseif ($permission == 'deny') {
$this->deny($role, $controller, $action, $assertion);
} else {
throw new \Exception('No valid permission defined: ' . $permission);
}
}
} elseif (is_string($roleConfig)) {
if ($action == 'all') {
$action = null;
}
if ($permission == 'allow') {
$this->allow($roleConfig, $controller, $action);
} elseif ($permission == 'deny') {
$this->deny($roleConfig, $controller, $action);
} else {
throw new \Exception('No valid permission defined: ' . $permission);
}
}
}
}
}
return $this;
}
...
AclFactory
AclFactory
namespace Authorization\Acl\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Authorization\Acl\Acl;
class AclFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('Config');
$assertions = [
'UserIsOwner' => $serviceLocator->get('Assertion\UserIsOwner')
];
$routeMatch = $serviceLocator->get('Application')->getMvcEvent()->getRouteMatch();
$routeMatchParams = $routeMatch->getParams();
$service = new Acl($config, $assertions, $routeMatchParams);
return $service;
}
}
这篇关于如何建立在Zend框架2的变量值的ACL断言?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!