somnambulist/policy-bundle
Composer 安装命令:
composer require somnambulist/policy-bundle
包简介
An implementation of Laravel policies for Symfony Security
README 文档
README
Policy bundle provides a version of Laravels security policy implementation for Symfony projects. This includes the Security Voter and support classes for debugging / handling permissions and access checks.
Requirements
- PHP 8.4+
Installation
Install using composer, or checkout / pull the files from github.com.
- composer require somnambulist/policy-bundle
Usage
This bundle makes certain presumptions on how you will authorise users in your project. You should have a User object that follows the roles and permissions approach, where permissions can be assigned to roles and/or the User. How you then store and fetch these are entirely up to you.
Provided your User (that implements the standard Symfony UserInterface) can provide access to methods defined in interfaces provided in this bundle, you can take advantage of policy objects and automatic resolution of these objects.
To begin with: you must add to your User object:
- Somnambulist\Bundles\PolicyBundle\Contracts\CanCheckPermissions
- Somnambulist\Bundles\PolicyBundle\Contracts\CanCheckRoles
These provide basic methods for checking if a User can perform an action, and if they have a role.
The implementation is left up to you to sort out, and if checking multiple permissions should require all or not to pass checks.
Next: you define your policies. You can place these anywhere in your project, though a dedicated "Policies" folder is recommended. If you are following a modular approach or Domain Driven Design based context, you can add the policies to your infrastructure layer, or however you want.
Regardless you should then add to your services.yaml (or however you define your services), a new resource that will reference the policies (policies are service objects). Policies must implement the PolicyInterface and will be automatically tagged and associated with the service classes in this bundle.
Finally: you can use the standard Symfony access checks as you normally would, including passing objects through. The PolicyVoter will call the appropriate method on your policy class and do the resolution based on how you set it up.
Making Policies
A policy object is a class that implements the Somnamblist\Bundles\PolicyBundle\Contracts\PolicyInterface.
The policy then provides the access checks on the subject provided.
Any policy is a service object, so you are not limited to just the passed User / Subject, you can use dependency injection to add repositories and other services to allow for fine-grained access control to resources e.g. by record ownership, date ranges etc.
The most basic form of a policy looks like:
use Somnambulist\Bundles\PolicyBundle\Policies\AbstractPolicy; use Symfony\Component\Security\Core\User\UserInterface; class DocumentPolicy extends AbstractPolicy { public const string MANAGE = 'documents.manage'; public const string DESTROY = 'documents.destroy'; public function supports(): array { return ['document', 'documents',]; } public function dependencies(): array { return []; } public function manage(UserInterface $user, mixed $subject): bool { return $user->can(self::MANAGE); } public function destroy(UserInterface $user, mixed $subject): bool { return $user->can(self::DESTROY); } }
This defines a policy that will operate with "document" objects. Two main permissions are defined to manage (create, view, update, publish, etc), and destroy. For better control "manage" could be split into separate permissions for create, edit, update, view, search, publish, etc. This is left up to your implementation, though class constants are strongly encouraged to prevent typing errors.
The next part is the policy actions; two have been defined that correspond to the manage and destroy permissions. You can have any number of actions defined on your policy to offer fine-grained programmatic control of access to the subject. These methods will be called by the voter and several forms are supported:
- the camel name e.g. can_create_document -> canCreateDocument()
- the method name as-is e.g. manage -> manage()
Policy Dependencies
Sometimes certain actions are dependent on having another permission; policies allow defining a required permission that is needed to use another permission. This is intended to be used in an admin panel to ensure that a given permission makes sense to be granted. For example: continuing the document example, documents can have files. To be able to manage files for a document, you should have the document manage role.
Dependencies are defined in an array format, where the key is the permission and the value, the dependency. If all
permissions need a dependency, a * can be used. For example:
use Somnambulist\Bundles\PolicyBundle\Policies\AbstractPolicy; use Symfony\Component\Security\Core\User\UserInterface; class FilePolicy extends AbstractPolicy { public const string MANAGE = 'documents.files.manage'; public const string DESTROY = 'documents.documents.destroy'; public function supports(): array { return ['file', 'files',]; } public function dependencies(): array { return [ '*' => DocumentPolicy::MANAGE, self::DESTROY => self::MANAGE, ]; } public function manage(UserInterface $user, $subject): bool { return $user->can(self::MANAGE); } public function destroy(UserInterface $user, $subject): bool { return $user->can(self::DESTROY); } }
In this example: the file destroy is also dependent on having the file manage permission.
The dependencies can be resolved using the PolicyResolverService::resolveDependenciesForPermissions(). Pass in the
permission to resolve permissions for.
Before Policy
Pre-authorization can be done by implementing the BeforePolicy contract. This can be used to e.g. allow full access
to a given role or specific user, or to do some other auth check. This should return true to allow, false to deny,
and null to defer to the policy.
Syncing Permissions to Roles
Policy bundle includes a console command for synchronising all permissions to a given role. This requires implementing the RoleRepository interface and adding it to your services. This defines 2 methods, the second being the method to sync permissions to a role.
The command will pull all policies and extract the constants (by default, this can be changed by implementing the provides() method on the policy) and then pass them to the role. This is useful to sync any code changes to your DB and ensure that the permissions are pre-assigned to a given role e.g. root or administrator.
Note that the internals of storing permissions are left to your implementation.
You must manually add the commands to your services.yaml as they depend on your RoleRepository implementation.
Tests
PHPUnit 12+ is used for testing. Run tests via vendor/bin/phpunit.
Contributing
Contributions are welcome! Fork the repository and make a PR back. Please ensure that your code is formatted
using PSR-12 coding standards, and all PHP files include declare(strict_types=1); on the opening <?php tag.
If in doubt about any code-style convention, look at the existing files and follow along.
This library currently targets PHP 8.4.X.
If adding new functionality ensure the README.md file is updated with your changes and include appropriate
tests and if possible, language translations with English as the primary requirement.
For bug fixes a failing case must be included in a test. Changes without appropriate tests or that cannot be replicated may be rejected.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 5
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-14