本章的目的是给出一个更深入的 ACL 系统的观点,并解释其背后的一些设计理念。
设计概念
Symfony2实例化的安全功能对象是建立在访问控制列表概念之上的。每个域对象实例都有他们自己的ACL。ACL实例有着一个访问控制项的详细列表(ACEs),该列表用来指定访问权限。
Symfony2的ACL系统专注于两个主要目标:
- 为你的域对象提供一个有效的方法去检索和更改大量的ACLs/ACEs。
- 提供一个方法,可以方便地确定用户是否被允许在一个域对象上具备执行相关操作的权限。
第一点明确表明,Symfony2中ACL系统的主要功能之一就是高效检索ACLs/ACEs。这非常重要,因为每个ACL有多条ACEs、同时它还以类树型的方式从其他ACL中继承。因此,虽然我们没有指定ORM,但是默认直接使用Doctrine的DBAL与你的连接实现交互。
Object Identities(对象标识)
ACL系统是完全与你的域对象分离的。它们甚至不需要保存在同一个数据库或同一台主机中。为了实现这种分离,在ACL系统里你的对象被认为是对象标识。任何时候,在你想检索域对象的ACL时,ACL系统都会事先为你的域对象创建一个对象标识,然后将该对象标识传递到ACL提供器作进一步处理。
Security Identities(安全标识)
与对象标识类似,但表现为你应用程序中的用户或角色。每个角色或用户都拥有各自的安全标识。
Database Table Structure(数据表结构)
(ACL系统)使用下列五个数据表来实现。在一个典型的应用程序中这些表按记录数从小到大排列。
- acl_security_identities:该表记录所有拥有ACEs的安全标识(SID)。默认实现附带了两个安全标识:RoleSecurityIdentity和UserSecurityIdentity。
- acl_classes: 该表将类名映射成唯一id,该id可以被其他数据表引用。
- acl_object_identities:数据表中的每条记录都表示一个单独的域对象实例。
- acl_object_identity_ancestors: 该表允许我们用一种非常高效的方式去确定一条ACL的所有父类,也就是可以迭代地确定该ACL继承了哪些ACL。
- acl_entries:该数据表包含所有的ACEs。该表通常拥有最多的记录。在包含数千万条记录的情况下不会显著影响性能。
访问控制项范围
访问控制项在应用时有不同的范围。在Symfony2中我们有两个基本的范围。
- Class-Scope: 类范围:这些项应用于拥有相同类的所有对象上。
- Object-Scope: 对象范围:在前面的章节中我们使用过这个范围,它仅用于指定的对象。
有时候,你只能将ACE应用到对象的特定字段里。比如说,你想ID只能被管理员而不是客户服务查看。那么要解决这个问题,我们需要添加两个额外的子范围:
- Class-Field-Scope: 类字段范围:这些项应用于拥有相同类的所有对象上,但仅仅是对象的特定字段。
- Object-Field-Scope: 对象字段范围:这些项应用于指定对象,但仅限于该对象的特定字段。
Pre-Authorization Decisions(预授权决策)
预授权决策是指任何方法或安全动作执行前就已判断,这证明AccessDecisionManager服务被使用,该服务也用于基于角色的达到授权决策。像角色一样,ACL系统添加一些新的属性去检查不同的权限。
内建权限映射
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 |
Permission Attributes vs. Permission Bitmasks(权限属性vs权限位掩码)
AccessDecisionManager使用属性和使用角色是一样的。通常,这些属性其实是用一串整型位掩码的总和来表示的。另一方面在ACL系统内部,整数位掩码被用来在数据库中保存用户权限,并且使用位掩码操作执行权限检查非常快速。
Extensibility(扩展性)
上述权限映射并不一成不变,理论上完全可以随意替代。然而,它将涵盖你所遇到的绝大多数问题,并且可以与其它Bundle相互协作。因此,我们还是鼓励你,坚持我们对它的期望。
Post Authorization Decisions(后授权决策)
后授权决策是发生在安全方法执行之后,通常还包含该方法返回的域对象。在调用提供器之后照样允许去修改或过滤返回前的域对象。
由于PHP语言的限制,已授权功能还未被纳入到核心安全组件中。尽管如此,实验性质的 JMSSecurityExtraBundle 已经添加了这些功能。查看它的文档以便进一步了解它是怎么实现的。
Process for Reaching Authorization Decisions (达到授权决策的过程)
ACL类提供两种方法去判断一个安全标识是否具有要求的掩码,isGranted和isFieldGranted。当ACL从这两种方法之一接收到授权请求,它就把这个请求委派给PermissionGrantingStrategy的实现。这样就允许你替换掉已达到但未实际更改的ACL类自身的权限决策方式。
PermissionGrantingStrategy首先检查所有对象范围的ACEs,如果没有匹配,则检查类范围的ACEs,如果还未匹配,将会重复在父ACL上的ACEs的检查过程。如果父ACL不存在,则抛出异常。