caridea / acl
一个访问控制库的小虾米
Requires
- php: >=7.1.0
Requires (Dev)
- phpunit/phpunit: ^6.0.0
README
Caridea是一个微小的PHP应用程序库。当你只需要一些辅助手而不需要一个完整的框架时,你可以使用这个小虾米。
这是其访问控制组件。你可以从任何你希望的地方创建权限列表。
安装
您可以使用Composer安装此库
$ composer require caridea/acl
- 此项目的master分支(版本3.x)需要PHP 7.1,没有依赖。
- 此项目的2.x版本需要PHP 7.0,没有依赖。
- 此项目的1.x版本需要PHP 5.5,没有依赖。
合规性
此库的版本将符合语义版本控制。
我们的代码旨在符合PSR-1、PSR-2和PSR-4。如果您发现任何与标准合规性相关的问题,请发送pull请求!
文档
定义
我们的权限API处理三个概念:主体、谓词和目标。
一个目标是可以被保护的东西。它有一个类型和一个标识符。它可以是数据库中的记录、应用程序中的控制器方法或URL。
一个主体是允许或拒绝访问的用户或角色。caridea-acl
附带两种类型的Subject
:主体和角色。例如,当前认证的用户有一个带有用户名的主体Subject
,还有几个带有角色名称的角色Subject
(例如admin
、user
、us-citizen
)。
一个谓词是Subject
可以在Target
上执行的操作(例如读取、创建、提交)。
Target
和Subject
是类,不是接口。由于我们打算使ACL不可变且可能可序列化,我们宁愿你不在自己的域类上添加接口。
示例
你必须创建自己的ACL加载器。我们绝对不包含存储和检索ACL的任何逻辑。
为什么?嗯,根据我们的经验,应用程序越大,对任何可能具有权限的记录序列化和存储ACL就越低效。我们发现,大多数情况下,应用程序的业务规则由记录属性决定,例如谁创建了什么记录,谁是部门的经理等等。
通过编写自己的Loader
,你可以非常详细地控制你的权限模型是如何提供的。
class MyLoader implements \Caridea\Acl\Loader { public function supports(Target $target) { return $target->getType() == 'foobar'; } public function load(Target $target, array $subjects, Service $service) { // some custom method to load my database record try { $record = MyRecord::loadFromDatabase($target->getId()); } catch (\Exception $e) { throw new \Caridea\Acl\Exception\Unloadable("Could not load record", 0, $e); } // load the parent record's ACL $parent = $service->get(new Target('foobar', $record['parent']), $subjects); // create the rules and return the final constructed ACL $rules = []; foreach ($subjects as $subject) { if ($subject->getType() == 'role' && $subject->getId() == 'admin') { // allow "admin" role for all permissions $rules[] = Rule::allow($subject); } elseif ($subject->getType() == 'role' && $subject->getId() == 'user') { // allow "user" role the read permission $rules[] = Rule::allow($subject, ['read']); } elseif ($subject->getType() == 'principal' && $subject->getId() == $record['owner']) { // allow the record owner CRUD permissions $rules[] = Rule::allow($subject, ['create', 'read', 'update', 'delete']); } } return new RuleAcl($target, $subjects, $rules, $parent); } }
然后将它们全部组合在一起。
// A list of all of your custom loaders $loaders = [new MyLoader()]; // Use the Cache Strategy to cache lookups $strategy = new \Caridea\Acl\CacheStrategy( new \Caridea\Acl\DelegateStrategy($loaders); ); $service = new \Caridea\Acl\Service($strategy); $subjects = MyClass::getSubjects(); // determine which subjects the user has $target = new Target('foobar', 123); $allowed = $service->can($subjects, 'delete', $target); try { $service->assert($subjects, 'delete', $target); } catch (\Caridea\Acl\Exception\Forbidden $e) { // not allowed! }
例如,您可以考虑使用依赖注入(例如使用caridea/container
)将所有加载器和Service
类连接起来。