SpringSecurity ACL持久化: Hibernate implementation of Spring Security ACL

本文重点描述如何基于hibernate在micrite 中 实现SS(Spring Security) ACL,相关软件版本为 spring-security-2.0.5.RELEASE 和micrite-0.11 。实现 的过程中,借鉴了下面三个例子:

  • contacts 联系人管理(重点参考)
    SS 的官方例子,控制不同用户对联系人的查看、修改、删除、管理权限。
  • dms 文档管理系统
    SS 的官方例子,和contract相比,功能相对简单,主要是体现了ACL继承的概念,例如文档的ACL权限可继承自所在目录的权限。
  • springstart 职员、客户的帐户管理(重点参考)
    denksoft 提供的基于postgresql的例子,有详细的说明文档 。

它们都采用SS默认的JDBC对ACL数据做持久化,而micrite持久层采用hibernate,如要实现ACL,需要重新实现SS默认的 ACL数据持久化接口,否则一个系统里就会有两种持久化方式(就像springstart一样),这有点难以接受。
SS的开发组曾对这个问题做过讨论,似乎短期内都没有修改的计划,所以,只能自己动手了。

建表

实现ACL需要建下面4张表:
acl_sid
acl_class
acl_object_identity
acl_entry

表结构的说明请参考 Schema Documentation 和 ER Diagram (基于derby)。
micrite使用velocity 模板 生成多种数据库脚本,保存在安装包的如下目录。
path: ./dbscripts

创建实体类

除了为上面的4张表建立相应的实体类之外,再建一个抽象类AbstractSecureObject , 目的是如果有多个受ACL保护的对象,不用在applicationContext-security.xml 文件里一一配 置,只需配置一个AbstractSecureObject,让其他受保护的实体类继承它。
AbstractSecureObject 只需要一个ID属性,让ACL可以获得受保护对象实例的ID值。

package org.gaixie.micrite.beans

增加DAO

为每个ACL实体类增加相应的DAO接口,及实现类。

package org.gaixie.micrite.security.dao
IAclSidDAO.java
IAclClassDAO.java
IAclObjectIdentityDAO.java
IAclEntryDAO.java
package org.gaixie.micrite.security.dao.hibernate
AclSidDAOImpl.java
AclClassDAOImpl.java
AclObjectIdentityDAOImpl.java
AclEntryDAOImpl.java

方法的说明请参见 micrite API文档 。

实现ACL数据持久化接口

我们需要实现两个ACL负责数据持久化的接口:

  • AclService 负责ACL实例的读取。
  • MutableAclService 负责创建和存储ACL实例。

首先,先创建一个我们自己的接口 ISecurityAclService , 目的是当新增一个受保护的对象实例时,统一调用此接口实现权限信息的持久化,同时让它继承SS的MutableAclService接口,所有下面会提 到。

接下来,创建两个Acl的数据持久化接口的实现类:

package org.gaixie.micrite.security.service.impl
AclServiceImpl.java
MutableAclServiceImpl.java
  • AclServiceImpl
    重点是重新实现AclService接口的一个方法
    public Map readAclsById(ObjectIdentity[] objects, Sid[] sids);
    SS中此方法默认实现,是通过调用一个名为BasicLookupStrategy 的 类来完成ACL实例信息的读取,这里我们直接通过调用相关的DAO,来实现此功能。省去BasicLookupStrategy类的原因是SS基于 JDBC获取数据,除了需要一些ANSI SQL之外,还要将得到的ResultSet结果集转换为相应的ACL实例,而我们采用Hibernate,直接通过DAO取出来就是对象实例,代码要比 默认的实现简单很多。(总算体现出Hibernate的好处了!!!)
  • MutableAclServiceImpl
    此类所有方法都需要基于hibernate重写,由于它实现的是自定义的ISecurityAclService接口,所以要比SS默认的JDBC多实现 两个方法:
    public void addPermission(AbstractSecureObject securedObject
        , Permission permission, Class clazz);
    public void addPermission(AbstractSecureObject securedObject
        , Sid recipient, Permission permission, Class clazz);

如果你了解上面ACL4个实体类的含义,并且熟悉Hibernate,会很容易理解这两个实现类,可以对照SS默认的JDBC实现。
当前micrite还没有实现AclCache接口,它可以大幅提升获取Acl实例的性能。

修改相关的xml配置文件

最后修改两个配置文件。

  • applicationContext-security.xml
    此配置文件相比没有ACL之前,主要是增加了afterInvocationManager的相关内容,用来处理在被拦截方法执行后,对返回的结果集进行 ACL过滤。
  • applicationContext-security-bean.xml
    此配置文件唯一需要注意的是 securityMutableAclService ,它实际对应着SS配置文件中的aclService,他们都是ACL数据持久化接口MutableAclService的实现类,由于我们采用 Spring自动装载的方式,所以不需要构造参数。它在applicationContext-security.xml 文件 中被频繁引用。

增加一个角色AFTER_ACL_COLLECTION_READ ,以后所有需要进行ACL结果集过滤的方法都绑定到此 角色。
到目前为止,我们已经完成了所有的ACL修改。

测试ACL

下面的步骤将实现:不同的用户只能看到自己拥有在的角色。管理员组(ROLE_ADMIN)可以看到所有的角色。

  1. 选择一个要进行ACL保护的实体类Role , 让Role继承AbstractSecureObject
  2. 添加要拦截的方法并绑定到角色AFTER_ACL_COLLECTION_READ ,通过界面或者SQL命令都可以。 注意拦截的方法至少有一个是返回Role对象结果集,如List(Role)Set(Role) 等。 可参见:
  3. 修改RoleServiceImpl 类 中的add(..), delete(..) 方法,在增加或删除Role之后,也增加或删除相应的ACL对象。通过调用 ISecurityAclServicede的方法可以很简单的实现。
  4. 编译、运行修改后的代码,用admin登录系统,增加几个Role和User,然后用不同的User登录,看看结果是否正确。

参考文档

[1] http://code.google.com/p/micrite/wiki/Permissions
[2] http://en.wikipedia.org/wiki/Access_Control_List

你可能感兴趣的:(SpringSecurity ACL持久化: Hibernate implementation of Spring Security ACL)