mimmi20 / mezzio-generic-authorization-rbac
为mezzio-generic-authorization提供laminas-permissions-rbac适配器。
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0
- laminas/laminas-permissions-rbac: ^3.6.0
- mimmi20/mezzio-generic-authorization: ^3.0.6
- psr/container: ^1.1.2 || ^2.0.2
- psr/http-message: ^1.0.1 || ^2.0
Requires (Dev)
- ext-ctype: *
- ext-dom: *
- ext-simplexml: *
- ext-tokenizer: *
- ext-xml: *
- ext-xmlwriter: *
- infection/infection: ^0.27.11 || ^0.28.1
- laminas/laminas-servicemanager: ^4.1.0
- mimmi20/coding-standard: ^5.2.43
- nikic/php-parser: ^4.19.1 || ^5.0.2
- phpstan/extension-installer: ^1.4.3
- phpstan/phpstan: ^1.12.3
- phpstan/phpstan-deprecation-rules: ^1.2.0
- phpstan/phpstan-phpunit: ^1.4.0
- phpunit/phpunit: ^10.5.26
- rector/rector: ^1.2.5
- rector/type-perfect: ^0.2.0
- symplify/phpstan-rules: ^13.0.1
- tomasvotruba/cognitive-complexity: ^0.2.3
- tomasvotruba/type-coverage: ^0.3.1
- tomasvotruba/unused-public: ^0.3.11
Suggests
- laminas/laminas-servicemanager: to use the factories
Conflicts
README
代码状态
此库为mezzio-generic-authorization提供laminas-rbac适配器。
安装
您可以使用Composer安装mezzio-generic-authorization-rbac库。
composer require mimmi20/mezzio-generic-authorization-rbac
介绍
此组件为基于角色的访问控制 (RBAC) 授权抽象提供了 mezzio-generic-authorization 库。
RBAC基于角色的概念。在一个Web应用中,用户有一个身份(例如,用户名,电子邮件等)。然后每个已标识的用户都有一个或多个角色(例如,管理员,编辑器,访客)。每个角色都有一个执行一个或多个操作(例如,访问URL,执行特定的Web API调用)的权限。
在一个典型的RBAC系统中
- 身份有一个或多个角色。
- 角色请求访问一个权限。
- 权限被赋予一个角色。
因此,RBAC有以下模型
- 身份和角色之间的多对多关系。
- 角色和权限之间的多对多关系。
- 角色可以有父角色。
RBAC系统的第一个要求是身份。在我们的场景中,用户由mezzio-authentication提供的认证系统生成。该库在用户认证时提供一个名为 Mezzio\Authentication\UserInterface
的PSR-7请求属性。RBAC系统使用此实例来获取有关用户身份的信息。
配置RBAC系统
您可以使用以下配置文件配置您的RBAC
// config/autoload/authorization.local.php return [ // ... 'mezzio-authorization-rbac' => [ 'roles' => [ 'administrator' => [], 'editor' => ['administrator'], 'contributor' => ['editor'], ], 'permissions' => [ 'contributor' => [ 'admin.dashboard', 'admin.posts', ], 'editor' => [ 'admin.publish', ], 'administrator' => [ 'admin.settings', ], ], ], ];
在上面的示例中,我们设计了一个包含3个角色(管理员,编辑器,贡献者)的RBAC系统。我们定义了以下角色层次结构
管理员
没有父角色。编辑器
的父角色是管理员
。这意味着管理员
继承了编辑器
的权限。贡献者
的父角色是编辑器
。这意味着编辑器
继承了贡献者
的权限,按照此链,管理员
继承了贡献者
的权限。
对于每个角色,我们指定了一个权限数组。如您所注意到的,权限只是一个字符串;它可以代表任何东西。在我们的实现中,这个字符串代表路由名称。这意味着贡献者
角色可以访问admin.dashboard
和admin.posts
路由,但不能访问分配给编辑器
角色的admin.publish
路由和分配给管理员
角色的admin.settings
路由。
如果您想为每个权限更改授权逻辑,您可以编写自己的Mimmi20\Mezzio\GenericAuthorization\AuthorizationInterface
实现。该接口定义了以下方法
public function isGranted(string $role, string $resource, ?string $privilege = null, ?\Psr\Http\Message\ServerRequestInterface\ServerRequestInterface $request = null): bool;
其中 $role
是角色,$resource
是资源,$privilege
是权限,$request
是用于授权的PSR-7 HTTP请求。
本库使用 laminas/laminas-permissions-rbac 库实现 RBAC 系统。此 RBAC 实现不支持权限。如果您想了解更多关于此库的用法,请阅读博客文章 使用 laminas-permissions-rbac 管理权限。
动态断言
在某些情况下,您可能需要根据特定的 HTTP 请求授权一个角色。例如,假设您有一个“编辑”角色,该角色可以添加/更新/删除内容管理系统 (CMS) 中的页面。我们希望阻止“编辑”修改他们未创建的页面。
这种类型的授权称为 动态断言,并且通过 laminas-permissions-rbac 的 Laminas\Permissions\Rbac\AssertionInterface
实现。
为了使用它,此包提供了 LaminasRbacAssertionInterface
,它扩展了 Laminas\Permissions\Rbac\AssertionInterface
namespace Mezzio\Authorization\Rbac; use Psr\Http\Message\ServerRequestInterface; use Laminas\Permissions\Rbac\AssertionInterface; interface LaminasRbacAssertionInterface extends AssertionInterface { public function setRequest(ServerRequestInterface $request) : void; }
Laminas\Permissions\Rbac\AssertionInterface
定义了以下内容
namespace Laminas\Permissions\Rbac; interface AssertionInterface { public function assert(Rbac $rbac, RoleInterface $role, string $permission) : bool; }
回到我们的用例,我们可以构建一个类来管理“编辑”授权要求,如下所示
use Mimmi20\Mezzio\GenericAuthorization\Rbac\LaminasRbacAssertionInterface; use App\Service\Article; use Laminas\Permissions\Rbac\Rbac; use Laminas\Permissions\Rbac\RoleInterface; use Psr\Http\Message\ServerRequestInterface; class EditorAuth implements LaminasRbacAssertionInterface { public function __construct(Article $article) { $this->article = $article; } public function setRequest(ServerRequestInterface $request): void { $this->request = $request; } public function assert(Rbac $rbac, RoleInterface $role, string $permission): bool { $user = $this->request->getAttribute(UserInterface::class, false); return $this->article->isUserOwner($user->getIdentity(), $this->request); } }
其中 Article
是一个类,它检查被识别的用户是否是 HTTP 请求中引用的文章的所有者。
如果您使用 SQL 数据库管理文章,则 isUserOwner()
的实现可能如下所示
public function isUserOwner(string $identity, ServerRequestInterface $request): bool { // get the article {article_id} attribute specified in the route $url = $request->getAttribute('article_id', false); if (! $url) { return false; } $sth = $this->pdo->prepare( 'SELECT * FROM article WHERE url = :url AND owner = :identity' ); $sth->bindParam(':url', $url); $sth->bindParam(':identity', $identity); if (! $sth->execute()) { return false; } $row = $sth->fetch(); return ! empty($row); }
要将 Article
依赖项传递到您的断言中,您可以使用一个 Factory 类来生成 EditorAuth
类的实例,如下所示
use App\Service\Article; class EditorAuthFactory { public function __invoke(ContainerInterface $container) : EditorAuth { return new EditorAuth( $container->get(Article::class) ); } }
然后配置服务容器使用 EditorAuthFactory
指向 EditorAuth
,如下所示
return [ 'dependencies' => [ 'factories' => [ // ... EditorAuth::class => EditorAuthFactory::class ] ] ];
许可协议
此包使用 MIT 许可协议授权。
请参阅 LICENSE.md
。