ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # 访问控制列表(ACL) `Phalcon\Acl` 提供简单轻量级的ACL管理以及附加的权限。[访问控制列表](http://en.wikipedia.org/wiki/Access_control_list)(ACL)允许应用程序控制对其区域和来自请求的底层对象的访问。建议您阅读有关ACL方法的更多信息,以便熟悉其概念。 总之,ACL具有角色和资源。资源是遵守ACL为其定义的权限的对象。角色是请求访问资源的对象,ACL机制可以允许或拒绝访问。 ## 创建ACL 该组件最初用于内存。这提供了易用性和访问列表的每个方面的速度。`Phalcon\Acl` 构造函数将第一个参数作为用于检索与控制列表相关的信息的适配器。使用内存适配器的示例如下: ```php <?php use Phalcon\Acl\Adapter\Memory as AclList; $acl = new AclList(); ``` 默认情况下, `Phalcon\Acl` 允许访问尚未定义的资源。为了提高访问列表的安全级别,我们可以将拒绝级别定义为默认访问级别。 ```php <?php use Phalcon\Acl; // Default action is deny access $acl->setDefaultAction( Acl::DENY ); ``` ## 将角色添加到ACL 角色是可以或不可以访问访问列表中的某些资源的对象。例如,我们将角色定义为组织中的人员组。`Phalcon\Acl\Role` 类可用于以更结构化的方式创建角色。让我们在最近创建的列表中添加一些角色: ```php <?php 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才能理解应该控制的内容。 ```php <?php 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(即哪些角色可以访问哪些资源)。这部分非常重要,特别是考虑到您的默认访问级别`allow`或`deny`。 ```php <?php // 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 列表完全定义后。我们可以查询它以检查角色是否具有给定的权限。 ```php <?php // 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'); ``` ## 基于功能的访问 您还可以添加自定义函数作为第4个参数,该函数必须返回布尔值。使用`isAllowed()`方法时将调用它。您可以将参数作为关联数组传递给`isAllowed()`方法作为第4个参数,其中key是我们定义的函数中的参数名称。 ```php <?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', [ 'a' => 4, ] ); // Returns false $acl->isAllowed( 'Guests', 'Customers', 'search', [ 'a' => 3, ] ); ``` 此外,如果您未在`isAllowed()`方法中提供任何参数,则默认行为将为`Acl::ALLOW`。您可以使用方法`setNoArgumentsDefaultAction()`更改它。 ```php <?php use Phalcon\Acl; // 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`传递。您的类必须为`roleName`实现`Phalcon\Acl\RoleAware`,为`resourceName`实现`Phalcon\Acl\ResourceAware`。 我们的 `UserRole` 类 ```php <?php 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` 类 ```php <?php 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()`方法中使用它们。 ```php <?php 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()`中访问自定义函数中的这些对象。它们按函数类型自动绑定到参数。 ```php <?php 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`提供的继承来构建复杂的角色结构。角色可以从其他角色继承,从而允许访问超集或资源子集。要使用角色继承,在列表中添加该角色时,需要将继承的角色作为方法调用的第二个参数传递。 ```php <?php 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,会话,文本文件或数据库表中,以便可以随意加载它们,而无需重新定义整个列表。你可以这样做: ```php <?php 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 :('; } ``` 建议在开发期间使用Memory适配器,并在生产中使用其他适配器之一。 ## 事件 `Phalcon\Acl` 能够将事件发送到`EventsManager`(如果存在)。使用“acl”类型触发事件。返回布尔值false时的某些事件可能会停止活动操作。支持以下事件: | 事件名称 | 触发 | Can stop operation? | | ----------------- | ------------------------------------------------------- |:-------------------:| | beforeCheckAccess | 在检查角色/资源是否具有访问权限之前触发 | Yes | | afterCheckAccess | 在检查角色/资源是否具有访问权限之后触发 | No | 以下示例演示如何将侦听器附加到此组件: ```php <?php 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适配器或扩展现有ACL适配器。