sirix/mezzio-rbac
Composer 安装命令:
composer require sirix/mezzio-rbac
包简介
RBAC authorization package for Mezzio framework with optional attribute-based support
README 文档
README
RBAC authorization package for Mezzio with PSR-15 middleware and optional PHP attribute integration.
Installation
composer require sirix/mezzio-rbac
Package is auto-registered via extra.laminas.config-provider.
Core Concepts
Actor
Current subject is represented by ActorInterface.
use Sirix\Mezzio\Rbac\Actor\Actor; $actor = new Actor(['editor', 'moderator']);
Guest fallback is provided by Sirix\Mezzio\Rbac\Actor\GuestActor.
Authorization paths
The package has two authorization paths:
| Use case | Service |
|---|---|
| HTTP request authorization | RequestGuardInterface / AuthorizeMiddleware |
| Non-HTTP service or CLI authorization | GuardInterface |
GuardInterface remains request-independent. It uses ActorProviderInterface and is useful from services, CLI commands, or application-managed contexts.
AuthorizeMiddleware uses RequestGuardInterface so it can authorize against the actor stored on the current PSR-7 request.
Guard
Main non-HTTP authorization entrypoint:
use Sirix\Mezzio\Rbac\Contract\GuardInterface; $guard->allows('posts.update'); $guard->denies('admin.panel'); $guard->authorize('posts.delete');
authorize() throws Sirix\Mezzio\Rbac\Exception\AuthorizationException with HTTP status 403.
Request Guard
HTTP-aware authorization entrypoint:
use Psr\Http\Message\ServerRequestInterface; use Sirix\Mezzio\Rbac\Contract\RequestGuardInterface; final readonly class PostHandler { public function __construct(private RequestGuardInterface $guard) {} public function handle(ServerRequestInterface $request): ResponseInterface { $this->guard->authorize($request, 'posts.update', [ 'postId' => $request->getAttribute('id'), ]); // ... } }
For route-level protection, prefer AuthorizeMiddleware or #[Can].
Permissions
Permissions use dot-notation and wildcard matching:
posts.readposts.updateadmin.users.deleteposts.*(greedy match)admin.*.delete(exact segment count)
Example:
use Sirix\Mezzio\Rbac\Contract\PermissionsInterface; use Sirix\Mezzio\Rbac\Rule\ForbidRule; $permissions->addRole('editor'); $permissions->associate('editor', 'posts.*'); $permissions->associate('editor', 'posts.delete', ForbidRule::class);
Resolution rules:
- exact match beats wildcard;
- more specific wildcard beats broader wildcard;
- latest association wins when specificity is equal;
- another actor role may still grant access if one role forbids it.
Conflict Resolution: Allow wins over Deny
The package follows an "Allow wins over Deny" policy. If an actor has multiple roles, access is granted if at least one role allows the permission.
Example: if a user has both user allowed posts.read and banned forbidden posts.read, the user still has access because the user role grants it.
Wildcard Matching
Permissions use dot-notation and support greedy terminal wildcard matching:
posts.*matchesposts.read,posts.update, and nested resources likeposts.read.history.admin.*grants access to all sub-resources of any depth.- Non-terminal wildcards, for example
admin.*.delete, still require exact segment positioning.
Rules
Built-in rules:
Sirix\Mezzio\Rbac\Rule\AllowRuleSirix\Mezzio\Rbac\Rule\ForbidRule
Custom rules implement Sirix\Mezzio\Rbac\Contract\RuleInterface:
use Sirix\Mezzio\Rbac\Contract\ActorInterface; use Sirix\Mezzio\Rbac\Contract\RuleInterface; final class OwnPostRule implements RuleInterface { public function allows(ActorInterface $actor, string $permission, array $context): bool { return ($context['ownerId'] ?? null) === ($context['userId'] ?? null); } }
Then associate it with a permission:
$permissions->associate('user', 'posts.update', OwnPostRule::class);
HTTP Integration
Actor resolution for HTTP requests
AuthorizeMiddleware resolves the actor from the current request through RequestActorProviderInterface.
The default provider reads this request attribute:
'rbac' => [ 'request_actor_attribute' => 'sirix.authentication.actor', ]
This default matches sirix/mezzio-authentication, which stores the authenticated actor in sirix.authentication.actor.
If the request attribute contains an RBAC ActorInterface, it is used directly. If it contains an authentication-like object with getRoles(), it is adapted to an RBAC actor. Missing or invalid actor values fall back to GuestActor.
ContainerActorProvider is still available for non-request usage through GuardInterface, but it should not be used to resolve the current HTTP user.
Metadata resolution
AuthorizeMiddleware resolves permission metadata in this order:
- request attribute
sirix.rbac.permission; - matched route option
sirix.rbac.permission; - if missing or empty, pass through without authorization.
Context follows the same order:
- request attribute
sirix.rbac.context; - matched route option
sirix.rbac.context; - empty array.
Context values map request attributes into rule context:
[
'postId' => 'id', // context['postId'] = $request->getAttribute('id')
]
With standard Mezzio routing
Register AuthorizeMiddleware in your route pipeline and set permission/context as route options:
use Sirix\Mezzio\Rbac\Middleware\AuthorizeMiddleware; use Sirix\Mezzio\Rbac\RbacAttribute; $app->post('/posts/:id', [ AuthorizeMiddleware::class, PostHandler::class, ], 'post.update')->setOptions([ RbacAttribute::Permission->value => 'posts.update', RbacAttribute::Context->value => ['postId' => 'id'], ]);
You can also set request attributes before AuthorizeMiddleware runs. Request attributes take precedence over route options.
With sirix/mezzio-routing-attributes
When used with sirix/mezzio-routing-attributes:^1.0, #[Can] implements RouteAttributeModifierInterface. It injects AuthorizeMiddleware into the route pipeline and stores permission/context in route options.
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use Sirix\Mezzio\Rbac\Attribute\Can; use Sirix\Mezzio\Routing\Attributes\Attribute\Post; #[Post('/posts/:id', name: 'post.update')] #[Can('posts.update', ['postId' => 'id'])] final class PostHandler implements RequestHandlerInterface { public function handle(ServerRequestInterface $request): ResponseInterface { // Authorization has already run before the handler. } }
No manual middleware registration is needed for routes discovered by sirix/mezzio-routing-attributes.
Integration with sirix/mezzio-authentication
sirix/mezzio-authentication writes the current actor to request attribute sirix.authentication.actor. RBAC uses that attribute by default, so the usual route pipeline is:
AuthenticateMiddleware
-> request attribute sirix.authentication.actor
-> AuthorizeMiddleware
-> RequestGuard
-> permission lookup/rules
With attributes:
use Sirix\Mezzio\Authentication\Attribute\Authenticated; use Sirix\Mezzio\Rbac\Attribute\Can; use Sirix\Mezzio\Routing\Attributes\Attribute\Get; #[Get('/admin', name: 'admin')] #[Authenticated] #[Can('admin.access')] final class AdminHandler implements RequestHandlerInterface { // ... }
Expected behavior:
- anonymous user is stopped by authentication;
- authenticated non-admin user receives
403; - authenticated admin user receives
200.
Manual authorization from services
For services without a request, use GuardInterface:
use Sirix\Mezzio\Rbac\Contract\GuardInterface; final readonly class PostService { public function __construct(private GuardInterface $guard) {} public function deletePost(string $postId): void { $this->guard->authorize('posts.delete', [ 'postId' => $postId, ]); } }
Storage Boundary
The package depends on contracts, not on concrete persistence.
Public storage contract:
Sirix\Mezzio\Rbac\Contract\PermissionStoreInterface
Read-only lookup contract used by authorization internals:
Sirix\Mezzio\Rbac\Contract\PermissionLookupInterface
Default implementation:
Sirix\Mezzio\Rbac\InMemoryPermissionStore
Later adapters can replace storage without changing the guard API.
Extensibility
Custom non-request actor provider
Use ActorProviderInterface for non-request authorization through GuardInterface:
use Sirix\Mezzio\Rbac\Actor\Actor; use Sirix\Mezzio\Rbac\Contract\ActorInterface; use Sirix\Mezzio\Rbac\Contract\ActorProviderInterface; final readonly class MyActorProvider implements ActorProviderInterface { public function __construct(private MyAuthService $auth) {} public function getActor(): ActorInterface { $user = $this->auth->getIdentity(); return new Actor($user?->getRoles() ?? ['guest']); } }
Custom request actor provider
Use RequestActorProviderInterface for HTTP authorization through RequestGuardInterface / AuthorizeMiddleware:
use Psr\Http\Message\ServerRequestInterface; use Sirix\Mezzio\Rbac\Actor\Actor; use Sirix\Mezzio\Rbac\Contract\ActorInterface; use Sirix\Mezzio\Rbac\Contract\RequestActorProviderInterface; final readonly class MyRequestActorProvider implements RequestActorProviderInterface { public function getActor(ServerRequestInterface $request): ActorInterface { $user = $request->getAttribute('user'); return new Actor($user?->roles() ?? ['guest']); } }
Register it in your dependencies:
'dependencies' => [ 'factories' => [ RequestActorProviderInterface::class => MyRequestActorProviderFactory::class, ], ],
Custom Permission Store
Implement PermissionStoreInterface to load permissions from a database, cache, or another source:
use Sirix\Mezzio\Rbac\Contract\PermissionAssociationInterface; use Sirix\Mezzio\Rbac\Contract\PermissionStoreInterface; final readonly class DatabasePermissionStore implements PermissionStoreInterface { public function associationsForRole(string $role): array { // Fetch from DB and map to PermissionAssociation objects. } // ... implement other methods }
Custom Rules
As shown in the Rules section, implement RuleInterface to add dynamic logic to permissions. Rules are resolved through RuleResolver, which can use the PSR-11 container or instantiate rule classes directly.
Main Components
GuardInterface/GuardRequestGuardInterface/RequestGuardActorProviderInterfaceRequestActorProviderInterfaceRequestAttributeActorProviderPermissionsPermissionLookupInterfacePermissionMatcherRuleResolverInMemoryPermissionStoreAuthorizeMiddlewareRbacAttribute#[Can(...)]
sirix/mezzio-rbac 适用场景与选型建议
sirix/mezzio-rbac 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 434 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 05 月 08 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「authorization」 「middleware」 「attributes」 「permissions」 「rbac」 「psr-15」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 sirix/mezzio-rbac 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 sirix/mezzio-rbac 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 sirix/mezzio-rbac 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Shoot aims to make providing data to your templates more manageable
Ory-Hydra OAuth 2.0 Client Provider for The PHP League OAuth2-Client
A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.
A library that allows you to easily use the PHP-VCR library in your PHPUnit tests.
This Package provides some usefully console features like the attribute syntax for arguments and options, validation, auto ask and casting.
Slim Framework 3 CSRF protection middleware utilities
统计信息
- 总下载量: 434
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 44
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-05-08