-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RBAC module #1
Comments
ModelNew aggregates: <?php
namespace SixtyEightPublishers\UserBundle\Domain\Role;
class Role implements AggregateRootInterface
{
use DeletableAggregateRootTrait;
private RoleId $id;
private Name $name;
/** RoleHasParent[] */
private Collection $parents;
private Resources $resources;
// the role cannot be deleted if the property is set to TRUE
private bool $persistent;
// the role has automatically access to everything if the property is set to TRUE, Resources
private bool $admin;
} <?php
namespace SixtyEightPublishers\UserBundle\Domain\Role;
/** Association between Role and Role */
class RoleHasParent
{
private string $id;
private Role $role;
private RoleId $parentId;
} <?php
namespace SixtyEightPublishers\UserBundle\Domain\User;
/** Association between User and Role */
class UserHasRole
{
private string $id;
private User $$user;
private RoleId $roleId;
} The object <?php
namespace SixtyEightPublishers\UserBundle\Domain\Role\ValueObject;
final class Resources
{
/** Resource[] */
private array $resources = [];
public function withPrivilege(string $resourceName, string $privilege): self {}
public function withoutPrivilege(string $resourceName, string $privilege): string {}
public function equals(self $resources): bool {}
}
final class Resource
{
private string $name;
/** string[] */
private array $privileges = [];
public function withPrivilege(string $privilege): self {}
public function withoutPrivilege(string $privilege): string {}
public function equals(self $resource): bool {}
} The value object will be stored in the database as JSON like: [
{
"name": "projects",
"privileges": [
"read"
]
},
{
"name": "categories",
"privileges": [
"read",
"write"
]
}
] Currently, the User aggregate contains a property An application resources & privilegesEach application has different resources and privileges so the resources must be provided by an application or an administration module (in the future). <?php
namespace SixtyEightPublishers\UserBundle\Application\Acl;
interface ResourceInterface
{
public static function name(): string;
public function privileges(): array;
}
abstract class AbstractResource implements ResourceInterface
{
private ?array $privileges = NULL;
public function privileges(): array
{
if (NULL === $this->privileges) {
$reflection = new ReflectionClass(static::class);
$this->privileges = array_values($reflection->getConstants());
}
return $this->privileges;
}
} In the application: <?php
final class ProjectResource extends AbstractResource
{
public const READ = 'read';
public const WRITE = 'write';
public const DELETE = 'delete';
public static function name(): string
{
return 'project';
}
} services:
- ProjectResource All resources can be injected into the services by array of type Authorizator<?php
namespace SixtyEightPublishers\UserBundle\Application\Acl;
interface AuthorizatorInterface
{
public function isAllowed(array $roles, string $resource, string $privilege): bool;
}
final class Authorizator implements AuthorizatorInterface
{
public function addRole(string $name, array $parents = []): void {}
public function addResource(ResourceInterface $resource): void {}
public function allow(string $role, string $resource, array $privileges = []): void {}
public function isAllowed(array $roles, string $resource, string $privilege): bool
{
# resolve
}
}
final class LazyAuthorizator implements AuthorizatorInterface
{
private QueryBusInterface $queryBus;
private ?AuthorizatorInterface $inner = NULL;
public function __construct(QueryBusInterface $queryBus)
{
$this->queryBus = $queryBus;
}
public function isAllowed(array $roles, string $resource, string $privilege): bool
{
return $this->getInner()->isAllowed($roles, $resource, $privilege);
}
private function getInner(): AuthorizatorInterface
{
if (NULL !== $this->inner) {
return $this->inner;
}
$a = new Authorizator();
# fill the authorization
return $this->inner = $a;
}
} The "generated" Authorizator should be cached in the future. Nette bridge: <?php
namespace SixtyEightPublishers\UserBundle\Bridge\Nette\Acl;
final class Authorizator implements Nette\Security\Authorizator
{
private AuthorizatorInterface $authorizator;
public function __construct(AuthorizatorInterface $authorizator)
{
$this->authorizator = $authorizator;
}
public function isAllowed($role, $resource, $privilege): bool
{
return $this->authorizator->isAllowed([(string) $role], (string) $resource, (string) $privilege);
}
} Usage<?php
$container->getByType(AuthorizatorInterface::class)->isAllowed(['admin'], ProjectResource::name(), ProjectResource::DELETE);
$container->getByType(Nette\Security\Authorizator::class)->isAllowed('admin', ProjectResource::name(), ProjectResource::DELETE);
$user = $container->getByType(Nette\Security\User::class);
$user->isAllowed(ProjectResource::name(), ProjectResource::DELETE); |
References
The text was updated successfully, but these errors were encountered: