将资源对象映射到其各自的策略类是策略解析器处理的行为。我们提供了一些解析器来帮助您入门,但您可以通过实现 Authorization\Policy\ResolverInterface
来创建自己的解析器。内置的解析器是
MapResolver
允许您将资源名称映射到其策略类名称,或映射到对象和可调用对象。
OrmResolver
基于约定,针对常见的 ORM 对象应用策略解析。
ResolverCollection
允许您将多个解析器聚合在一起,并按顺序搜索它们。
MapResolver
允许您将资源类名称映射到策略类名称、策略对象或工厂可调用对象。
use Authorization\Policy\MapResolver;
$mapResolver = new MapResolver();
// Map a resource class to a policy classname
$mapResolver->map(Article::class, ArticlePolicy::class);
// Map a resource class to a policy instance.
$mapResolver->map(Article::class, new ArticlePolicy());
// Map a resource class to a factory function
$mapResolver->map(Article::class, function ($resource, $mapResolver) {
// Return a policy object.
});
OrmResolver
是 CakePHP ORM 的基于约定的策略解析器。OrmResolver 应用以下约定
策略位于 App\Policy
策略类以 Policy
类后缀结尾。
OrmResolver 可以解析以下对象类型的策略
实体 - 使用实体类名。
表 - 使用表类名。
查询 - 使用查询的 repository()
的返回值获取类名。
在所有情况下,都会应用以下规则
资源类名用于生成策略类名。例如 App\Model\Entity\Bookmark
将映射到 App\Policy\BookmarkPolicy
插件资源将首先检查应用程序策略,例如 App\Policy\Bookmarks\BookmarkPolicy
用于 Bookmarks\Model\Entity\Bookmark
。
如果找不到应用程序覆盖策略,则会检查插件策略。例如:Bookmarks\Policy\BookmarkPolicy
对于表对象,类名转换将导致 App\Model\Table\ArticlesTable
映射到 App\Policy\ArticlesTablePolicy
。查询对象将调用其 repository()
方法,并根据生成的结果表类生成策略。
OrmResolver 支持通过其构造函数进行自定义
use Authorization\Policy\OrmResolver;
// Change when using a custom application namespace.
$appNamespace = 'App';
// Map policies in one namespace to another.
// Here we have mapped policies for classes in the ``Blog`` namespace to be
// found in the ``Cms`` namespace.
$overrides = [
'Blog' => 'Cms',
];
$resolver = new OrmResolver($appNamespace, $overrides)
ResolverCollection
允许您将多个解析器聚合在一起
use Authorization\Policy\ResolverCollection;
use Authorization\Policy\MapResolver;
use Authorization\Policy\OrmResolver;
$ormResolver = new OrmResolver();
$mapResolver = new MapResolver();
// Check the map resolver, and fallback to the orm resolver if
// a resource is not explicitly mapped.
$resolver = new ResolverCollection([$mapResolver, $ormResolver]);
您可以通过实现 Authorization\Policy\ResolverInterface
来实现自己的解析器,这需要定义 getPolicy($resource)
方法。
自定义解析器有用的一个示例场景是,当从 AuthComponent
迁移时,将授权插件与基于控制器的访问控制桥接。首先,我们需要创建一个通配策略,它将调用我们的控制器方法
// in src/Policy/ControllerHookPolicy.php
namespace App\Policy;
class ControllerHookPolicy
{
public function __call(string $name, array $arguments)
{
/** @var ?\Authorization\Identity $user */
[$user, $controller] = $arguments;
return $controller->isAuthorized($user?->getOriginalData());
}
}
我们的策略类使用 __call
,以便它可以处理我们控制器中的所有操作。我们的策略调用我们控制器上的 isAuthorized()
方法,为我们提供了与现有逻辑的向后兼容性。接下来,我们将创建一个策略解析器,它将解析控制器以用于我们的自定义策略
// in src/Policy/ControllerResolver.php
namespace App\Policy;
use Authorization\Policy\ResolverInterface;
use Authorization\Policy\Exception\MissingPolicyException;
use Cake\Controller\Controller;
class ControllerResolver implements ResolverInterface
{
public function getPolicy($resource)
{
if ($resource instanceof Controller) {
return new ControllerHookPolicy();
}
throw new MissingPolicyException([get_class($resource)]);
}
}
创建完策略和解析器后,我们可以直接将解析器添加到我们的应用程序中,或者使用 ResolverCollection
将其与其他解析器结合起来。