spareparts / overseer
Attribute-based authorization manager.
Installs: 22 122
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 2
Forks: 2
Open Issues: 0
Requires
- php: >=5.5.0
- spareparts/enum: *@dev
Requires (Dev)
- mockery/mockery: ^0.9.6
- phpunit/phpunit: ~4
This package is auto-updated.
Last update: 2024-11-18 18:59:10 UTC
README
Action-based authorization manager
Quick disclaimer: This is pretty much a work in progress. At this point this is more of a "proof-of-concept" than working code. Though the logic is sound and I fully intend to finish this into an awesome 1.0 release.
What is this and why should I care?
Overseer is an "action-based" auth manager, meaning it is based on authorizing possible "actions" (such as read, edit, delete, etc.) with given "subject" (such as Article, Product, Category etc.).
Overseer focuses on decoupling auth logic from the rest of the application. When solving problems as "user that is the owner of this product can edit it" other auth managers tend to wire the logic directly into the said product class or pile all possible actions (read, write, delete, ...) into one big method. Either way it breaks S of the SOLID principles (single responsibility principle) and that's where Overseer jumps in.
Basic building stones of Overseer are "voting assemblies", consisting of "voters". Each combination of action and subject can have (doesn't have to, though) its own voting assembly, thus separating concerns and responsibilities involved.
Installation
Composer
This is how we do it, boys.
composer require spareparts/overseer
Basic usage
Let's imagine we have an article site, and we want to make sure the admin can read the article always, while its author only unless it's not banned.
This is how we create the voting assembly for this specific subject and action. It contains four voters,
$assembly = new VotingAssembly(
$subjectName = 'article',
$actionName = 'read',
$strategy = StrategyEnum::FIRST_VOTE_DECIDES(),
$voters = [
new RoleVoter(VotingDecisionEnum::ALLOWED(), 'admin'),
new ClosureVoter(function (DummyArticle $article, IdentityContext $context) {
// allow the owner to edit
if ($subject->ownerId === $context->getId()) {
return new SingleVoterResult(VotingDecisionEnum::ALLOWED());
}
return null;
}),
new ClosureVoter(function (DummyArticle $article) {
// deny access if the article is banned
if ($subject->isBanned()) {
return new SingleVoterResult(VotingDecisionEnum::ALLOWED());
}
return null;
}),
new RoleVoter(VotingDecisionEnum::ALLOWED(), 'user'),
]
);
$authorizationManager = new GenericVotingManager([
// our article edit assembly
$assembly,
// other assemblies...
// ...
]);
Now let's use it
$context = new IdentityContext($userId, $userRoles);
$authorized = $authorizationManager->vote('edit', $article, $context);
if ($authorized->getDecision() === VotingDecisionEnum::ALLOWED()) {
// we can edit!
}