tobento / acl
1.0.8
2024-09-15 11:22 UTC
Requires
- php: >=8.0
- psr/container: ^1.0 || ^2.0
- tobento/service-helper-function: ^1.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- vimeo/psalm: ^4.0
README
ACL服务是一个简单的角色和用户级访问控制系统。
目录
入门
运行此命令添加Acl服务的最新版本。
composer require tobento/service-acl
要求
- PHP 8.0 或更高版本
亮点
- 框架无关,可与任何项目一起使用
- 自定义权限行为
- 解耦设计
简单示例
以下是一个使用Acl服务的简单示例。
use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\Authorizable; use Tobento\Service\Acl\AuthorizableAware; use Tobento\Service\Acl\Role; // User class example. class User implements Authorizable { use AuthorizableAware; public function __construct( protected string $name, ) {} } // Create Acl. $acl = new Acl(); // Adding rules. $acl->rule('articles.read') ->title('Article Read') ->description('If a user can read articles'); $acl->rule('articles.create'); $acl->rule('articles.update'); // Create role. $guestRole = new Role('guest'); // Adding permissions on role. $guestRole->addPermissions(['articles.read']); // Create and set user role. $user = (new User('Nick'))->setRole($guestRole); // Adding permissions on user. // If permissions are set on user, role permissions will not count anymore. $user->addPermissions(['articles.read']); // Set current user. $acl->setCurrentUser($user); // Adding additional permissions for the current user only. $acl->addPermissions(['articles.create']); // Check permissions for current user. if ($acl->can('articles.read')) { // user has permission to read articles. } // check permission for specific user. if ($acl->cant(key: 'articles.read', user: $user)) { // user has not permission to read articles. }
文档
规则
添加和获取规则。
use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\RuleInterface; // Create Acl. $acl = new Acl(); // Add default rule. $acl->rule('articles.read'); // Add custom rule. $acl->addRule(RuleInterface $rule); // Get rules. foreach($acl->getRules() as $rule) { $key = $rule->getKey(); $inputKey = $rule->getInputKey(); $title = $rule->getTitle(); $description = $rule->getDescription(); $area = $rule->getArea(); } // get specific rules $rule = $acl->getRule('articles.read');
默认规则
默认规则具有以下权限行为
use Tobento\Service\Acl\Acl; // Create Acl. $acl = new Acl(); $acl->rule('articles.read'); $acl->rule('articles.update'); // Create role. $role = new Role('guest'); // Create and set user role. $user = (new User('Nick'))->setRole($role); // Adding permissions on acl, only for current user. $acl->addPermissions(['articles.read']); // Adding permissions on role. $role->addPermissions(['articles.read']); // Adding permissions on user. // If permissions are set on user, role permissions will not count anymore. // Only acl and user specific permissions. $user->addPermissions(['articles.read']);
区域行为
use Tobento\Service\Acl\Acl; // Create Acl. $acl = new Acl(); $acl->rule('articles.read', 'frontend'); $acl->rule('articles.update', 'backend'); // Guest Role taking only frontend rules into account, // ignoring any permission from backend rules even if permission is given. $role = new Role('guest', ['frontend']); // Editor can have frontend and backend rules. $role = new Role('editor', ['frontend', 'backend']);
自定义默认规则
您可以为扩展特定规则行为轻松添加自定义处理程序。
use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\Authorizable; use Tobento\Service\Acl\AuthorizableAware; use Tobento\Service\Acl\Role; // User class example. class User implements Authorizable { use AuthorizableAware; public function __construct( protected string $name, ) {} } // Article class example class Article { public function __construct( protected string $name, protected array $roles = [], protected null|Authorizable $user = null ) {} public function getName(): string { return $this->name; } public function getUser(): null|Authorizable { return $this->user; } public function getRoles(): array { return $this->roles; } } // Create Acl. $acl = new Acl(); // Rule to check if user is allowed to access a specific resource. $acl->rule('resource') ->needsPermission(false) ->handler(function(Authorizable $user, null|Authorizable $resourceUser): bool { if (is_null($resourceUser)) { return false; } return $user === $resourceUser; }); // Rule to check if user has role for a specific resource. $acl->rule('has_role') ->needsPermission(false) ->handler(function(Authorizable $user, array $roles = []) { if (empty($roles)) { return true; } return in_array($user->role()->key(), $roles); }); $user = (new User('Nick'))->setRole(new Role('editor')); $acl->setCurrentUser($user); $article = new Article('About us', ['editor'], $user); // Check resource access. if ($acl->can('resource', [$article->getUser()])) { // user can access about page. } // Check resource role access. if ($acl->can('has_role', [$article->getRoles()])) { // user has the right role to access this resource. }
自定义规则
您可以为不同的权限策略轻松添加自定义规则。
您的规则必须实现以下RuleInterface。
/** * RuleInterface */ interface RuleInterface { /** * Get the key. * * @return string The key such as 'user.create'. */ public function getKey(): string; /** * Get the input key. May be used for form input. * * @return string The key such as 'user_create'. */ public function getInputKey(): string; /** * Get the title. * * @return string The title */ public function getTitle(): string; /** * Get the description. * * @return string The description */ public function getDescription(): string; /** * Get the area. * * @return string */ public function getArea(): string; /** * If the rule requires permissions to match the rule. * * @return bool */ public function requiresPermission(): bool; /** * Return if the rule matches the criteria. * * @param AclInterface * @param string A permission key 'user.create'. * @param array Any parameters for custom handler * @param null|Authorizable * @return bool True if rule matches, otherwise false */ public function matches( AclInterface $acl, string $key, array $parameters = [], ?Authorizable $user = null ): bool; }
让我们创建一个自定义规则,只允许具有特定权限的用户访问,忽略acl和角色权限。
use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\AclInterface; use Tobento\Service\Acl\RuleInterface; use Tobento\Service\Acl\Authorizable; use Tobento\Service\Acl\AuthorizableAware; use Tobento\Service\Acl\Role; // Custom rule class CustomRule implements RuleInterface { public function __construct( protected string $key, protected string $area, ) {} public function getKey(): string { return $this->key; } public function getInputKey(): string { return $this->key; } public function getTitle(): string { return $this->key; } public function getDescription(): string { return ''; } public function getArea(): string { return $this->area; } public function requiresPermission(): bool { return true; } public function matches( AclInterface $acl, string $key, array $parameters = [], ?Authorizable $user = null ): bool { $user = $user ?: $acl->getCurrentUser(); // not user at all if (is_null($user)) { return false; } // user needs a role. if (! $user->hasRole()) { return false; } // collect only user permissions. if (!$user->hasPermissions()) { return false; } $permissions = $user->getPermissions(); // permission check if (!in_array($key, $permissions)) { return false; } // area check if (!in_array($this->getArea(), $user->role()->areas())) { return false; } return true; } } // User class example. class User implements Authorizable { use AuthorizableAware; public function __construct( protected string $name, ) {} } // Create Acl. $acl = new Acl(); // Adding default rules. $acl->addRule(new CustomRule('articles.read', 'frontend')); $acl->addRule(new CustomRule('articles.create', 'frontend')); // Create role. $role = new Role('guest'); // Adding permissions on role does has no effect. $role->addPermissions(['articles.read']); // Create and set user role. $user = (new User('Nick'))->setRole($role); $user->addPermissions(['articles.create']); // Set current user. $acl->setCurrentUser($user); if ($acl->can('articles.create')) { // user has permission to read articles. }
权限
以下方法是实现Permissionable Interface或Authorizable Interface的对象上可用的。
- Tobento\Service\Acl\Acl::class
- Tobento\Service\Acl\Role::class
use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\Permissionable; use Tobento\Service\Acl\Authorizable; // Create Acl. $acl = new Acl(); // Set all permissions. $acl->setPermissions(['user.create', 'user.update']); // Adding more permissions. $acl->addPermissions(['user.delete']); $permissions = $acl->getPermissions(); // ['user.create', 'user.update', 'user.delete'] // Has any permissions at all. $hasPermissions = $acl->hasPermissions(); // Removing permissions. $acl->removePermissions(['user.delete']); // Has specific permission. $hasPermission = $acl->hasPermission('user.update');
在acl上检查权限的可用方法
use Tobento\Service\Acl\Acl; // Create Acl. $acl = new Acl(); // Check permissions for current user. if ($acl->can('articles.read')) { // user has permission to read articles. } // Check permission for specific user. if ($acl->cant(key: 'articles.read', user: $user)) { // user has not permission to read articles. } // You can check multiple permissions too. if ($acl->can('articles.create|articles.update')) { // user has permission to create and update articles. } // Multiple permissions with parameters. if ($acl->can('articles.create|resource', ['resource' => [$article->getUser()]])) { // user has permission to create and access the specific article. }
在Authorizable对象上检查权限
有关辅助函数的更多信息,请访问 tobento/helper-function
use Tobento\Service\HelperFunction\Functions; use Psr\Container\ContainerInterface; use Tobento\Service\Di\Container; use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\AclInterface; use Tobento\Service\Acl\Authorizable; use Tobento\Service\Acl\AuthorizableAware; use Tobento\Service\Acl\Role; // create container. $container = new Container(); // Set up Helper Function acl() for supporting // checking permission directly on Authorizable objects. $functions = new Functions(); $functions->set(ContainerInterface::class, $container); // Register Acl functions. $functions->register('dir/to/acl/functions.php'); // User class example. class User implements Authorizable { use AuthorizableAware; public function __construct( protected string $name, ) {} } // Create Acl. $acl = new Acl(); // Add Acl to container. $container->set(AclInterface::class, $acl); // Adding rules. $acl->rule('articles.read'); // Create role. $guestRole = new Role('guest'); // Adding permissions on role. $guestRole->addPermissions(['articles.read']); // Create and set user role. $user = (new User('Nick'))->setRole($guestRole); // Check permissions on user. if ($user->can('articles.read')) { // user has permission to read articles. } // check permission for specific user. if ($user->cant('articles.read')) { // user has not permission to read articles. }
角色
处理角色。
use Tobento\Service\Acl\Acl; use Tobento\Service\Acl\Role; use Tobento\Service\Acl\RoleInterface; use Tobento\Service\Acl\Roles; use Tobento\Service\Acl\RolesInterface; // Create Acl. $acl = new Acl(); // Set roles on acl for later reusage if needed. $acl->setRoles([ new Role('guest'), new Role('editor'), ]); // or $acl->setRoles(new Roles( new Role('guest'), new Role('editor'), )); // Get roles: $roles = $acl->roles(); var_dump($roles instanceof RolesInterface); // bool(true) // Iterate roles: foreach($acl->roles() as $role) { $key = $role->key(); $active = $role->active(); $areas = $role->areas(); $name = $role->name(); } // Get Specific role: $role = $roles->get('editor'); $role = $acl->getRole('editor'); // or // null|RoleInterface // Check if role exists: var_dump($roles->has('editor')); var_dump($acl->hasRole('editor')); // or // bool(true) // Sort roles returning a new instance: $roles = $roles->sort(fn(RoleInterface $a, RoleInterface $b): int => $a->name() <=> $b->name()); // Filter roles returning a new instance: $roles = $roles->filter(fn(RoleInterface $role): bool => $role->active()); // Filter by area roles returning a new instance: $roles = $roles->area('frontend'); // Filter (in)active roles returning a new instance: $roles = $roles->active(); $roles = $roles->active(false); // Returns a new instance only the roles specified: $roles = $roles->only(['editor']); // Returns a new instance except the roles specified: $roles = $roles->except(['editor']); // Add a role returning a new instance: $roles = $roles->add(new Role('admin')); // Remove a role returning a new instance: $roles = $roles->remove('editor'); // Get first role: $role = $roles->first(); // null|RoleInterface // Get all roles: $roles = $roles->all(); $roles = $acl->getRoles(); // or // array<string, RoleInterface>