> Symfony中文手册 > 如何使用先进的ACL概念

如何使用先进的ACL概念

超高难文档 本文档需要阅读Security Bundle中的ACL部分之源代码。同时对整个Security组件有深度认知才有可能付诸实战。

Security Voter可以包打天下

在博大精深的Symfony框架日趋“向末级程序员提供更好体验”的过程中,很多超高难的定制写法,被局限在特别复杂高端同时较少遇到的场合。ACL就是其中之一。如果你对此部分内容不很适应,可以先略过,这并不影响我们的日常开发。

当然仅凭这篇文档也是不可能写出漂亮的ACL应用的,还是要搞懂原理,多看那些用到了ACL的程序,比如FosCommentBundle或是SonataAdminBundle,逐步实践。

我们希望在后面能够提供给大家更多线索。

本文的目的,是深入了解ACL系统,并对其背后的一些设计决策进行解释。

设计理念 ¶

Symfony的对象实例,其安全能力是建立在 Access Control List(ACL)这一概念基础之上的。每一个DOMain object(域对象)都有它自己的ACL。ACL实例,持有一个Access Control Entries(ACEs)明细列表,用于做出访问决定(access decisions)。Symfony的ACL系统专注于两个主要目标:

  • 为你的域对象提供一种“高效地取出大量ACLs/ACEs”的方式,然后修改它们;

  • 提供一种“可以轻易判断某人是否可以对域对象进行操作”的方式。

如第一点所述,Symfony中ACL系统的主要能力之一,就是取出ACLs/ACEs时的极高性能。这极端重要,因为每个ACL可以有多个ACEs,还可以通过一种“类树状方式”(tree-like fashion)从别的ACL中进行继承。因此我们不借助ORM,默认的实现是直接用Doctrine的DBAL来与你的连接(connection)展开互动(译注:就是指ACL/ACEs的一切存取操作都是基于DBAL)。

Object Identities ¶

ACL系统是从你的域对象中完全解耦的。它们甚至不需要被保存在同一个数据库中或同一台服务器上。为了实现这种解耦,在ACL系统中,你的对象将通过object identity对象来呈现。每当你要取出一个域对象的ACL时,ACL系统首先要创建一个object identity(对象识别),然后将这个object identity对象,传入ACL provider作进一步处理。

Security Identities ¶

与对象识别相类似,但是它在程序中呈现的是一个用户(user),或是一个role(角色)。每一个role或用户,有其自己的安全识别(security identity)。

对于用户来说,security identity基于用户名。这意味着,无论什么原因,只要一个用户的username发生了改变,你必须确保security identity也得到更新。MutableAclProvider::updateUserSecurityIdentity()方法专门用来处理更新。

数据库的表结构 ¶

(ACL系统)的默认实现是使用以下五个数据表。这些表(在本文中)的排列顺序,是按照“在一个典型程序中,每个表的记录行数由少到多”来进行的。

  • acl_security_identities:该表记录了全部的security identity(SID)。默认的实现自带了两个security identity:RoleSecurityIdentityUserSecurityIdentity

  • acl_classes:该表将类名映射成唯一ID(而存储下来),该ID可以被其他数据表引用。

  • acl_object_identities:数据表中的每一条记录,呈现的一个单独的域对象实例。

  • acl_object_identity_ancestors:该表能够以一种极为高效的方式来确定出一个ACL的“所有父ACL”(ancestors)。

  • acl_entries:这个表包含了全部ACEs。这也是通常情况下“行数最多”的表。在千万级数据的条件下,不会显著影响性能。

ACE的SCOPE ¶

Access control entries可以应用到不同的scope(范围)。在Symfony中,基本上有两种不同的范围:

  • Class-Scope(类范围):这些ACEs适用于同一个类的所有对象。

  • Object-Scope(对象范围):在前面章节中我们用过一次这个scope,它只适用于一个特定的对象。

有时,你会发现有 “只把ACE应用到某个对象的特定字段中” 这样的需求。假设,你希望只有管理员能看到ID,而不能被客服看到。要解决这种常见问题,需要额外添加两个sub-scopes(子范围):

  • Class-Field-Scope(类字段范围):这些ACEs适用于同一个类的所有对象,但却只能作用于对象中的某个特定字段。

  • Object-Field-Scope(对象字段范围):这些ACEs适用于一个特定的对象,同时只能作用于该对象的某个特定字段。

Pre-Authorization Decisions ¶

所谓Pre-Authorization Decisions是指,在任何安全方法(security method,或安全动作[security action])调用之前就已经做出的决断,这用到了正统的AccessDecisionManager服务。AccessDecisionManager服务也用在“基于角色(based on roles)”的reaching authorization decisions(达成授权决断)。和roles一样,ACL系统添加了若干新的属性,用于检查不同的权限。

内建的Permission Map(权限映射) ¶

Attribute
(属性)
Intended Meaning
(意图)
Integer Bitmasks
(整型位掩码)
VIEW Whether someone is allowed to view the domain object.
是否允许某人查看域对象
VIEW, EDIT, OPERATOR, MASTER, or OWNER
EDIT Whether someone is allowed to make changes to the domain object.
是否允许某人修改域对象
EDIT, OPERATOR, MASTER, or OWNER
CREATE Whether someone is allowed to create the domain object.
是否允许某人创建域对象
CREATE, OPERATOR, MASTER, or OWNER
DELETE Whether someone is allowed to delete the domain object.
某人是否被允许删除域对象
DELETE, OPERATOR, MASTER, or OWNER
UNDELETE Whether someone is allowed to restore a previously deleted domain object.
是否允许某人恢复先前被删除的域对象
UNDELETE, OPERATOR, MASTER, or OWNER
OPERATOR Whether someone is allowed to perform all of the above actions.
是否允许某人执行上述全部操作。
OPERATOR, MASTER, or OWNER
MASTER Whether someone is allowed to perform all of the above actions, and in addition is allowed to grAnt any of the above permissions to others.
是否允许某人执行上述全部操作,同时他还能将以上任何一个权限授权给他人。
MASTER, or OWNER
OWNER Whether someone owns the domain object. An owner can perform any of the above actions andgrant master and owner permissions.
某人是否拥有该域对象。owner能执行上述任何一个操作 并且 能够(向他人)授予master和owner权限。
OWNER

Permission Attributes vs. Permission Bitmasks(权限属性 vs 权限位掩码) ¶

AccessDecisionManager在使用属性(attributes)时类似于它使用roles(角色)。通常,这些属性的实际呈现方式是“一系列聚合起来的整型位掩码(integer bitmasks)”。而另一方面,整型位掩码在ACL系统内部,被用来在数据库中高效地存储用户权限,并且使用超快的位掩码操作来执行访问检查(access checks)。

扩展性 ¶

上述权限映射并非一成不变,理论上完全可以随需替换之。然而,它(译注:指由integer bitmasks所构成permission maps)将涵盖你所遇到的绝大多数问题,并且可以与其他Bundles实现互用,建议你遵照其设计本意来使用之。

Post Authorization Decisions ¶

Post Authorization Decisions在(程序中的)安全(相关)方法(security method)被调用之后确立,一般还会包含这些方法所返回的domain object。在调用providers之后,域对象仍然可以在被返回之前接受修改和过滤。

由于PHP语言的限制,框架核心的安全组件还不具备后授权(post-authorization)的能力。尽管如此,实验性质的 JMSSecurityExtraBundle 已经添加了这些功能。参考它的文档以便进一步了解它是如何实现的。

达成Authorization Decisions的过程 ¶

ACL类提供两种方法去来决断一个security identity是否拥有所需的bitmasks,即 isGrantedisFieldGranted。当ACL通过其中的一种方法接收到授权请求(authorization request)时,它把这个请求委托给 PermissionGrantingStrategy 的一个实现。这就令你能够替换access dicisions的达成方式,而毋须真正修改ACL类本身。

PermissionGrantingStrategy 首先检查你所有的object-scope的ACEs,如果无有可用,则去检查object-scope的ACEs。如果仍无可用,进程将重复查找父ACL上的ACEs。若父ACL并不存在,一个异常会被抛出。