Списки управления доступом (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