大美食品/permissions

此包已被废弃且不再维护。没有建议的替代包。

2.0.1 2019-07-15 15:27 UTC

This package is auto-updated.

Last update: 2020-01-16 15:01:26 UTC


README

Downloads this Month Latest Stable Version

动机

此库的目的是为 isAllowed 评估添加特定于用户的数据。断言回调直接将 IUser 作为第一个参数传递。

这解决了Nette中本地ACL的最大“问题”

	$callback = function (IUser $user, $queriedRole, $queriedResource) {
		return $user->getEntity()->getId() === $queriedResource->getEntity()->getCreatorId();
	};

	// god can destroy world, but only the one he created
	$authorizator->allow('god', 'world', 'destroy', $callback);

此库的另一个方面是将授权者与 Nette\Security\User 分离,因为这绝对不是用户的责任来提供此功能。

免责声明

此库被编写得尽可能类似于Nette中的 Permission 类。然而,规则的评估是从头开始编写的。

因此

  • 不实现 Nette\Security\IAuthorizator(由于不同的 isAllowed 方法API,无法实现),
  • 可能会显著 较慢(但编写得很漂亮),
  • 无法保证其行为完全相同。

安装

composer require damejidlo/permission

配置

AccessListNeon

你自己的 AccessList 服务的示例实现。

class AccessList extends Authorizator
{
	/**
	 * @param string[][] $roles
	 */
	public function addRoles(array $roles)
	{
		foreach ($roles as $role => $parentRoles) {
			$this->addRole($role, $parentRoles);
		}
	}

	/**
	 * @param @param string[] $resources
	 */
	public function addResources(array $resources)
	{
		foreach ($resources as $resource) {
			$this->addResource($resource);
		}
	}

	/**
	 * @param string[][][] $directives
	 */
	public function addDirectives(array $directives)
	{
		foreach ($directives as $resource => $resourceDirectives) {
			foreach ($resourceDirectives as $privilege => $privilegeDirectives) {
				foreach ($privilegeDirectives as $roleIdentifier => $directiveType) {
					$this->createDirective($directiveType, $roleIdentifier, $resource, $privilege);
				}
			}
		}
	}

	public function someStuff()
	{
		$callback = function (IUser $user, $queriedRole, $queriedResource) {
			return $user->getEntity()->getId() === $queriedResource->getEntity()->getCreatorId();
		};

		// god can destroy world, but only the one he created
		$authorizator->allow('god', 'world', 'destroy', $callback);
	}
}

然后只需将其添加到你的 config.neon

parameters:
	acl:
		roles:
			writer: []
			reviewer: [writer]

		resources:
			- article

		directives:
			article:
				create:
					writer: allow
				publish:
					reviewer: allow

services:
	acl:
		class: YourProject\Security\AccessList
		setup:
			- addRoles(%acl.roles%)
			- addResources(%acl.resources%)
			- addDirectives(%acl.directives%)
			- someStuff() # here we can do some "cool stuff"

创建你的 AclUser

class AclUser extends Object implements IUser
{
	// Implement `getRoles` method
}

创建你自己的 Nette\Security\User

你需要创建你自己的 User 服务

class MyLoggedUser extends \Nette\Security\User
{
	/**
	 * @param IUserStorage $storage
	 * @param IAuthenticator|NULL $authenticator
	 */
	public function __construct(IUserStorage $storage, IAuthenticator $authenticator = NULL)
	{
		parent::__construct($storage, $authenticator); // No IAuthorizator here !!!
	}

	/**
	 * @inheritdoc
	 */
	public function isAllowed($resource = IAuthorizator::ALL, $privilege = IAuthorizator::ALL)
	{
		throw new LogicException('Use Damejidlo\ACL\Authorizator directly. User shouldn\'t have such a responsibility');
	}

	/**
	 * @inheritdoc
	 */
	public function isInRole($role)
	{
		throw new LogicException('Use Damejidlo\ACL\Authorizator directly. User shouldn\'t have such a responsibility');
	}

	/**
	 * @return AclUser
	 */
	public function getAclUser()
	{
		$entity = $this->getEntity(); // depens on your implementation
		return new AclUser($entity, $this->getRoles());
	}
}
services:
    user: Some\Namespace\MyLoggedUser

将你的授权者加载到模板中

最好的方法是创建你自己的 TemplateFactory。然后在 createTemplate 方法中调用

	/**
	 * @param Control|NULL $control
	 * @return Template
	 */
	public function createTemplate(Control $control = NULL)
	{
		$template = parent::createTemplate($control);

		// Some stuff (helper registration, etc...)

		$template->setParameters([
			'authorizator' => $this->authorizator,
		]);

		return $template;
	}

用法

现在,开始获利!

	// In some Presenter

	public function handleDestroy($worldId)
	{
		$world = $this->worldFinder->findWorld($worldId);
		$resource = new WorldResource($world);
		$permission = 'destroy';

		if (!$this->authorizator->isAllowed($this->user->getAclUser(), $resource, $permission) {
			throw new NotAllowedException($resource, $permission);
		}
	}