Acl的全称是Access Control List,俗称访问控制列表,是用以控制对象的访问权限的。其主要思想是将某个对象的某种权限授予给某个用户,或某种GrantedAuthority(可以简单的理解为某种角色),它们之间的关系都是多对多。如果某一个对象的某一操作是受保护的,那么在对该对象进行某种操作时就需要有对应的权限。
1.1 准备工作
使用Spring Security的Acl功能需要引入Acl相关的jar包。如果我们的应用是使用Maven构建的,则可以在应用的pom.xml文件中加入如下依赖。
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>${spring.security.version}</version>
</dependency>
此外,使用Spring Security的Acl时需要在数据库中建立四张表。在其官方文档中给出了一个基于数据库HSQLDB的建表语句。其脚本如下:
create table acl_sid (
id bigint generated by default as identity(start with 100) not null primary key,
principal boolean not null,
sid varchar_ignorecase(100) not null,
constraint unique_uk_1 unique(sid,principal) );
create table acl_class (
id bigint generated by default as identity(start with 100) not null primary key,
class varchar_ignorecase(100) not null,
constraint unique_uk_2 unique(class) );
create table acl_object_identity (
id bigint generated by default as identity(start with 100) not null primary key,
object_id_class bigint not null,
object_id_identity bigint not null,
parent_object bigint,
owner_sid bigint not null,
entries_inheriting boolean not null,
constraint unique_uk_3 unique(object_id_class,object_id_identity),
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );
create table acl_entry (
id bigint generated by default as identity(start with 100) not null primary key,
acl_object_identity bigint not null,ace_order int not null,sid bigint not null,
mask integer not null,granting boolean not null,audit_success boolean not null,
audit_failure boolean not null,
constraint unique_uk_4 unique(acl_object_identity,ace_order),
constraint foreign_fk_4 foreign key(acl_object_identity)
references acl_object_identity(id),
constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );
笔者使用的是Oracle数据库,其中没有boolean和主键自增功能,对于boolean类型都使用一位number表示。具体建表语句如下所示:
create table acl_sid (
id number not null primary key,
principal number(1) not null,
sid varchar(100) not null,
constraint unique_uk_1 unique(sid,principal) );
create table acl_class (
id number not null primary key,
class varchar(100) not null,
constraint unique_uk_2 unique(class) );
create table acl_object_identity (
id number not null primary key,
object_id_class number not null,
object_id_identity number not null,
parent_object number,
owner_sid number not null,
entries_inheriting number(1) not null,
constraint unique_uk_3 unique(object_id_class,object_id_identity),
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );
create table acl_entry (
id number not null primary key,
acl_object_identity number not null,ace_order int not null,sid number not null,
mask number(3) not null,granting number(1) not null,audit_success number(1) not null,
audit_failure number(1) not null,
constraint unique_uk_4 unique(acl_object_identity,ace_order),
constraint foreign_fk_4 foreign key(acl_object_identity)
references acl_object_identity(id),
constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );
新增记录时用于生成主键的sequence定义为:
create or replace sequence seq_acl_sid start with 1 increment by 1;
create or replace sequence seq_acl_class start with 1 increment by 1;
create or replace sequence seq_acl_object_identity start with 1 increment by 1;
create or replace sequence seq_acl_entry start with 1 increment by 1;
1.2 表功能介绍
如上所示,Spring Security的Acl功能需要使用到四张数据库表,分别为acl_sid、acl_class、acl_object_identity和acl_entry。
1.2.1表acl_sid
表acl_sid的结构如下所示:
字段名 |
类型 |
说明 |
id |
number |
主键 |
sid |
varchar |
字符串类型的sid |
principal |
boolean |
是否用户 |
表acl_sid是用来保存Sid的。对于Acl而言,有两种类型的Sid,一种是基于用户的Sid,叫PrincipalSid;另一种是基于GrantedAuthority的Sid,叫GrantedAuthoritySid。acl_sid表的sid字段存放的是用户名或者是GrantedAuthority的字符串表示。prinpal是用来区分对应的Sid是用户还是GrantedAuthority的。正如在前文所描述的那样,Acl中对象的权限是用来授予给Sid的,Sid有用户和GrantedAuthority之分,所以我们的对象权限是可以用来授予给用户或GrantedAuthority的。
1.2.2表acl_class
表acl_class的结构如下所示:
字段名 |
类型 |
说明 |
id |
number |
主键 |
class |
varchar |
对象类型的全限定名 |
表acl_class是用来保存对象类型的,字段class中保存的是对应对象的全限定名。Acl需要使用它来区分不同的对象类型。
1.2.3表acl_object_identity
表acl_object_identity的结构如下:
字段名 |
类型 |
描述 |
id |
number |
主键 |
object_id_class |
number |
关联acl_class,表示对象类型 |
object_id_identity |
number |
对象的主键,对于相同的class而言,其需要是唯一的。对象的主键默认需要是Long型,或者可以转换为Long型的对象,如Integer、Short等。 |
parent_object |
number |
父对象的id,关联acl_object_identity |
owner_sid |
number |
拥有者的sid,关联acl_sid |
entries_inheriting |
boolean |
是否继承父对象的权限。打个比方,删除对象childObj需要有delete权限,用户A他没有childObj的delete权限,但是他有childObj的父对象parentObj的delete权限,当entries_inheriting为true时,用户A同样可以删除childObj。 |
表acl_object_identity是用来存放需要进行访问控制的对象的信息的。其保存的信息有对象的拥有者、对象的类型、对象的主键、对象的父对象和是否继承父对象的权限。
1.2.4表acl_entry
表acl_entry的结构如下:
字段名 |
类型 |
说明 |
id |
number |
主键 |
acl_object_identity |
number |
对应acl_object_identity的id |
ace_order |
number |
所属Acl的权限顺序 |
sid |
number |
对应acl_sid的id |
mask |
number |
权限对应的掩码 |
granting |
boolean |
是否授权 |
audit_success |
boolean |
暂未发现其作用,Acl中有一个更新其值的方法,但未见被调用。 |
audit_failure |
boolean |
表acl_entry是用于存放具体的权限信息的,从表结构我们也可以看出来,其描述的就是某个主体(Sid)对某个对象(acl_object_identity)是否(granting)拥有某种权限(mask)。当同一对象acl_object_identity在acl_entry表中拥有多条记录时,就会使用ace_order来标记对应的顺序,其对应于往Acl中插入AccessControlEntry时的位置,在进行权限判断时也是依靠ace_order的顺序来进行的,ace_order越小的越先进行判断。ace是Access Control Entry的简称。
1.3 Acl主要接口
对于Acl而言,有两块比较核心的功能,一块是往对应的数据库表里面插数据,另一块是从数据库表里面取出对应的数据进行权限鉴定。要了解这些功能我们先来了解Acl中用到的主要接口。
l Sid:可以用来表示一个principal,或者是一个GrantedAuthority。其对应的实现类有表示principal的PrincipalSid和表示GrantedAuthority的GrantedAuthoritySid。其信息会保存在acl_sid表中。
l ObjectIdentity:ObjectIdentity表示Spring Security Acl中一个域对象,其默认实现类是ObjectIdentityImpl。ObjectIdentity并不是直接与acl_object_identity表相对应的,真正与acl_object_identity表直接相对应的是Acl。
l Acl:每一个领域对象都会对应一个Acl,而且只会对应一个Acl。Acl是将Spring Security Acl中使用到的四个表串联起来的一个接口,其中会包含对象信息ObjectIdentity、对象的拥有者Sid和对象的访问控制信息AccessControlEntry。在Spring Security Acl中直接与acl_object_identity表相关联的是Acl接口,因为acl_object_identity表中的数据是通过保存Acl来进行的。一个Acl对应于一个ObjectIdentity,但是会包含有多个Sid和多个AccessControlEntry,即一个Acl表示所有Sid对一个ObjectIdentity的所有AccessControlEntry。Acl的默认实现类是AclImpl,该类实现Acl接口、MutableAcl接口、AuditableAcl接口和OwnershipAcl接口。
l AccessControlEntry:一个AccessControlEntry表示一条访问控制信息,一个Acl中可以拥有多个AccessControlEntry。在Spring Security Acl中很多地方会使用ACE来简单的表示AccessControlEntry这个概念,比如insertAce其实表示的就是insert AccessControlEntry。每一个AccessControlEntry表示对应的Sid对于对应的对象ObjectIdentity是否被授权某一项权限Permission,是否被授权将使用granting进行区分。AccessControlEntry对应表acl_entry。
l Permission:在Acl中使用一个bit掩码来表示一个Permission。Spring Security的Acl中默认使用的是BasePermission,其中已经定义了0-4五个bit掩码,分别对应于1、2、4、8、16,代表五种不同的Permission,分别是read (bit 0)、write (bit 1)、create (bit 2)、delete (bit 3)和administer (bit 4)。如果已经定义好的这五个bit掩码不能满足需求,我们可以对BasePermission进行扩展,也可以实现自己的Permission。Spring Security Acl默认的实现最多可以支持32个不同的掩码。
l AclService:AclService是用来通过ObjectIdentity解析Acl的,其默认实现类是JdbcAclService。JdbcAclService底层操作是通过LookupStrategy来进行的,LookupStrategy的默认实现是BasicLookupStrategy。
l MutableAclService:MutableAclService是用来对Acl进行持久化的,其默认实现类是JdbcMutableAclService。JdbcMutableAclService是继承自JdbcAclService的,所以我们可以同时通过JdbcMutableAclService对Acl进行读取和保存。如果我们希望自己来实现Acl信息的保存的话,我们也可以不使用该接口。
1.4 配置AclService
AclService是使用Spring Security Acl功能的主入口。这里选择一个既可以从数据库读取Acl信息,又可以保存Acl信息到数据库的JdbcMutableAclService做示例。
JdbcMutableAclService只有一个构造方法,它接收三个参数,DataSource、LookupStrategy和AclCache。其对应配置信息如下所示ÿ