Spec-Zone.ru › Phalcon 3

Списки управления доступом (ACL)

Phalcon\Acl предоставляет простой и лёгкий способ управления списками управления доступом (ACL) и правами доступа к ним. Списки управления доступом (ACL) позволяют приложению контролировать доступ к своим областям и связанным объектам из запросов. Рекомендуется изучить методологию ACL для понимания её концепций.

В общем случае, ACL содержат роли и ресурсы. Ресурсы — это объекты, которые подчиняются правам доступа, определённым для них в ACL. Роли — это объекты, запрашивающие доступ к ресурсам, и ACL может разрешить или запретить им доступ.

Создание ACL

Этот компонент первоначально работает в памяти. Это обеспечивает удобство использования и скорость доступа ко всем аспектам списка. Конструктор Phalcon\Acl принимает в качестве первого параметра адаптер, используемый для извлечения информации, связанной со списком управления. Пример с использованием адаптера памяти показан ниже:

use Phalcon\Acl\Adapter\Memory as AclList;

$acl = new AclList();

По умолчанию Phalcon\Acl разрешает доступ к действию над ресурсами, которые ещё не определены. Для повышения уровня безопасности списка доступа можно определить уровень «отказа» в качестве уровня доступа по умолчанию.

use Phalcon\Acl;

// Default action is deny access
$acl->setDefaultAction(
    Acl::DENY
);

Добавление ролей в ACL

Роль — это объект, который может или не может получить доступ к определённым ресурсам в списке доступа. В качестве примера, мы определим роли как группы людей в организации. Класс Phalcon\Acl\Role доступен для создания ролей более структурированным способом. Добавим несколько ролей в наш недавно созданный список:

use Phalcon\Acl\Role;

// Create some roles.
// The first parameter is the name, the second parameter is an optional description.
$roleAdmins = new Role("Administrators", "Super-User role");
$roleGuests = new Role("Guests");

// Add "Guests" role to ACL
$acl->addRole($roleGuests);

// Add "Designers" role to ACL without a Phalcon\Acl\Role
$acl->addRole("Designers");

Как видите, роли определяются непосредственно без использования экземпляра.

Добавление ресурсов

Ресурсы — это объекты, для которых контролируется доступ. Обычно в приложениях MVC ресурсы ссылаются на контроллеры. Хотя это не обязательно, класс Phalcon\Acl\Resource можно использовать для определения ресурсов. Важно добавить связанные действия или операции к ресурсу, чтобы ACL понимал, что ему нужно контролировать.

use Phalcon\Acl\Resource;

// Define the "Customers" resource
$customersResource = new Resource("Customers");

// Add "customers" resource with a couple of operations

$acl->addResource(
    $customersResource,
    "search"
);

$acl->addResource(
    $customersResource,
    [
        "create",
        "update",
    ]
);

Определение контролей доступа

Теперь, когда у нас есть роли и ресурсы, пришло время определить ACL (т. е. какие роли могут получить доступ к каким ресурсам). Этот этап очень важен, особенно с учётом уровня доступа по умолчанию «разрешить» или «запретить».

// Set access level for roles into resources

$acl->allow("Guests", "Customers", "search");

$acl->allow("Guests", "Customers", "create");

$acl->deny("Guests", "Customers", "update");

Метод allow() указывает, что определённая роль получила разрешение на доступ к определённому ресурсу. Метод deny() делает обратное.

Запрос ACL

После того, как список будет полностью определён, мы можем запросить его, чтобы проверить, имеет ли роль данное разрешение или нет.

// Check whether role has access to the operations

// Returns 0
$acl->isAllowed("Guests", "Customers", "edit");

// Returns 1
$acl->isAllowed("Guests", "Customers", "search");

// Returns 1
$acl->isAllowed("Guests", "Customers", "create");

Доступ на основе функций

Также вы можете добавить в качестве четвёртого параметра свою пользовательскую функцию, которая должна возвращать булево значение. Она будет вызываться при использовании метода isAllowed(). Вы можете передать параметры в виде ассоциативного массива методу isAllowed() в качестве четвёртого аргумента, где ключ — имя параметра в нашей определённой функции.

// Set access level for role into resources with custom function
$acl->allow(
    "Guests",
    "Customers",
    "search",
    function ($a) {
        return $a % 2 === 0;
    }
);

// Check whether role has access to the operation with custom function

// Returns true
$acl->isAllowed(
    "Guests",
    "Customers",
    "search",
    [
        "a" => 4,
    ]
);

// Returns false
$acl->isAllowed(
    "Guests",
    "Customers",
    "search",
    [
        "a" => 3,
    ]
);

Также, если вы не предоставите никаких параметров в методе isAllowed(), то по умолчанию будет действовать Acl::ALLOW. Вы можете изменить это, используя метод setNoArgumentsDefaultAction().

use Phalcon\Acl;

<?php
// Set access level for role into resources with custom function
$acl->allow(
    "Guests",
    "Customers",
    "search",
    function ($a) {
        return $a % 2 === 0;
    }
);

// Check whether role has access to the operation with custom function

// Returns true
$acl->isAllowed(
    "Guests",
    "Customers",
    "search"
);

// Change no arguments default action
$acl->setNoArgumentsDefaultAction(
    Acl::DENY
);

// Returns false
$acl->isAllowed(
    "Guests",
    "Customers",
    "search"
);

Объекты как имя роли и имя ресурса

Вы можете передавать объекты в качестве roleName и resourceName. Ваши классы должны реализовывать Phalcon\Acl\RoleAware для roleName и Phalcon\Acl\ResourceAware для resourceName.

Наш класс UserRole

use Phalcon\Acl\RoleAware;

// Create our class which will be used as roleName
class UserRole implements RoleAware
{
    protected $id;

    protected $roleName;

    public function __construct($id, $roleName)
    {
        $this->id       = $id;
        $this->roleName = $roleName;
    }

    public function getId()
    {
        return $this->id;
    }

    // Implemented function from RoleAware Interface
    public function getRoleName()
    {
        return $this->roleName;
    }
}

И наш класс ModelResource

use Phalcon\Acl\ResourceAware;

// Create our class which will be used as resourceName
class ModelResource implements ResourceAware
{
    protected $id;

    protected $resourceName;

    protected $userId;

    public function __construct($id, $resourceName, $userId)
    {
        $this->id           = $id;
        $this->resourceName = $resourceName;
        $this->userId       = $userId;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getUserId()
    {
        return $this->userId;
    }

    // Implemented function from ResourceAware Interface
    public function getResourceName()
    {
        return $this->resourceName;
    }
}

Затем вы можете использовать их в методе isAllowed()

use UserRole;
use ModelResource;

// Set access level for role into resources
$acl->allow("Guests", "Customers", "search");
$acl->allow("Guests", "Customers", "create");
$acl->deny("Guests", "Customers", "update");

// Create our objects providing roleName and resourceName

$customer = new ModelResource(
    1,
    "Customers",
    2
);

$designer = new UserRole(
    1,
    "Designers"
);

$guest = new UserRole(
    2,
    "Guests"
);

$anotherGuest = new UserRole(
    3,
    "Guests"
);

// Check whether our user objects have access to the operation on model object

// Returns false
$acl->isAllowed(
    $designer,
    $customer,
    "search"
);

// Returns true
$acl->isAllowed(
    $guest,
    $customer,
    "search"
);

// Returns true
$acl->isAllowed(
    $anotherGuest,
    $customer,
    "search"
);

Также вы можете получить доступ к этим объектам в своей пользовательской функции в allow() или deny(). Они автоматически привязываются к параметрам по типу в функции.

use UserRole;
use ModelResource;

// Set access level for role into resources with custom function
$acl->allow(
    "Guests",
    "Customers",
    "search",
    function (UserRole $user, ModelResource $model) { // User and Model classes are necessary
        return $user->getId == $model->getUserId();
    }
);

$acl->allow(
    "Guests",
    "Customers",
    "create"
);

$acl->deny(
    "Guests",
    "Customers",
    "update"
);

// Create our objects providing roleName and resourceName

$customer = new ModelResource(
    1,
    "Customers",
    2
);

$designer = new UserRole(
    1,
    "Designers"
);

$guest = new UserRole(
    2,
    "Guests"
);

$anotherGuest = new UserRole(
    3,
    "Guests"
);

// Check whether our user objects have access to the operation on model object

// Returns false
$acl->isAllowed(
    $designer,
    $customer,
    "search"
);

// Returns true
$acl->isAllowed(
    $guest,
    $customer,
    "search"
);

// Returns false
$acl->isAllowed(
    $anotherGuest,
    $customer,
    "search"
);

Вы по-прежнему можете добавлять любые пользовательские параметры в функцию и передавать ассоциативный массив в методе isAllowed(). Порядок также не имеет значения.

Наследование ролей

Вы можете создавать сложные структуры ролей, используя наследование, которое предоставляет Phalcon\Acl\Role. Роли могут наследоваться от других ролей, что позволяет получить доступ к наборам или подмножествам ресурсов. Для использования наследования ролей вам нужно передать унаследованную роль в качестве второго параметра вызова метода при добавлении этой роли в список.

use Phalcon\Acl\Role;

// ...

// Create some roles

$roleAdmins = new Role("Administrators", "Super-User role");

$roleGuests = new Role("Guests");

// Add "Guests" role to ACL
$acl->addRole($roleGuests);

// Add "Administrators" role inheriting from "Guests" its accesses
$acl->addRole($roleAdmins, $roleGuests);

Сериализация списков ACL

Для повышения производительности экземпляры Phalcon\Acl можно сериализовать и хранить в APC, сессии, текстовых файлах или таблице базы данных, чтобы их можно было загружать по мере необходимости, не переопределяя весь список. Вы можете сделать это следующим образом:

use Phalcon\Acl\Adapter\Memory as AclList;

// ...

// Check whether ACL data already exist
if (!is_file("app/security/acl.data")) {
    $acl = new AclList();

    // ... Define roles, resources, access, etc

    // Store serialized list into plain file
    file_put_contents(
        "app/security/acl.data",
        serialize($acl)
    );
} else {
    // Restore ACL object from serialized file
    $acl = unserialize(
        file_get_contents("app/security/acl.data")
    );
}

// Use ACL list as needed
if ($acl->isAllowed("Guests", "Customers", "edit")) {
    echo "Access granted!";
} else {
    echo "Access denied :(";
}

Рекомендуется использовать адаптер памяти во время разработки и один из других адаптеров в производстве.

События ACL

Phalcon\Acl может отправлять события в EventsManager, если он присутствует. События генерируются с помощью типа «acl». Некоторые события при возвращении false могут остановить активную операцию. Поддерживаются следующие события:

Имя события Срабатывание Можно остановить операцию?
beforeCheckAccess Срабатывает перед проверкой доступа роли/ресурса Да
afterCheckAccess Срабатывает после проверки доступа роли/ресурса Нет

Следующий пример демонстрирует, как прикрепить слушателей к этому компоненту:

use Phalcon\Acl\Adapter\Memory as AclList;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;

// ...

// Create an event manager
$eventsManager = new EventsManager();

// Attach a listener for type "acl"
$eventsManager->attach(
    "acl:beforeCheckAccess",
    function (Event $event, $acl) {
        echo $acl->getActiveRole();

        echo $acl->getActiveResource();

        echo $acl->getActiveAccess();
    }
);

$acl = new AclList();

// Setup the $acl
// ...

// Bind the eventsManager to the ACL component
$acl->setEventsManager($eventsManager);

Реализация собственных адаптеров

Интерфейс Phalcon\Acl\AdapterInterface должен быть реализован для создания собственных адаптеров ACL или расширения существующих.

© 2011–2017 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/latest/reference/acl.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API