caridea/acl

一个访问控制库的小虾米

3.0.0 2018-01-07 18:46 UTC

This package is not auto-updated.

Last update: 2024-09-10 03:36:59 UTC


README

Caridea是一个微小的PHP应用程序库。当你只需要一些辅助手而不需要一个完整的框架时,你可以使用这个小虾米。

这是其访问控制组件。你可以从任何你希望的地方创建权限列表。

Packagist Build Status Scrutinizer Code Quality Code Coverage

安装

您可以使用Composer安装此库

$ composer require caridea/acl
  • 此项目的master分支(版本3.x)需要PHP 7.1,没有依赖。
  • 此项目的2.x版本需要PHP 7.0,没有依赖。
  • 此项目的1.x版本需要PHP 5.5,没有依赖。

合规性

此库的版本将符合语义版本控制

我们的代码旨在符合PSR-1PSR-2PSR-4。如果您发现任何与标准合规性相关的问题,请发送pull请求!

文档

定义

我们的权限API处理三个概念:主体、谓词和目标。

一个目标是可以被保护的东西。它有一个类型和一个标识符。它可以是数据库中的记录、应用程序中的控制器方法或URL。

一个主体是允许或拒绝访问的用户或角色。caridea-acl附带两种类型的Subject主体角色。例如,当前认证的用户有一个带有用户名的主体Subject,还有几个带有角色名称的角色Subject(例如adminuserus-citizen)。

一个谓词Subject可以在Target上执行的操作(例如读取创建提交)。

TargetSubject是类,不是接口。由于我们打算使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类连接起来。