spring security:访问控制列表来保护领域对象

之前提到的安全保护和权限控制都是只针对 URL 或是方法调用,只对一类对象起作用。而在有些情况下,不同领域对象实体所要求的权限控制是不同的。以第一类示例应用来说,系统中有报表这一类实体。由于报表的特殊性,只有具有角色 ROLE_PRESIDENT的用户才可以创建报表。对于每份报表,创建者可以设定其对于不同用户的权限。比如有的报表只允许特定的几个用户可以查看。对于这样的需求,就需要对每个领域对象的实例设置对应的访问控制权限。Spring Security 提供了对访问控制列表(Access Control List,ACL)的支持,可以很方便的对不同的领域对象设置针对不同用户的权限。

Spring Security 中的访问控制列表的实现中有 3 个重要的概念,对应于 4 张数据库表。

  • 授权的主体:一般是系统中的用户。由 ACL_SID表来表示。
  • 领域对象:表示系统中需要进行访问控制的实体。由 ACL_CLASS和 ACL_OBJECT_IDENTITY表来表示,前者保存的是实体所对应的 Java 类的名称,而后者保存的是实体本身。
  • 访问权限:表示一个用户对一个领域对象所具有的权限。由表 ACL_ENTRY来表示。

Spring Security 已经提供了参考的数据库表模式和相应的基于 JDBC 的实现。在大多数情况下,使用参考实现就可以满足需求了。类org.springframework.security.acls.jdbc.JdbcMutableAclService可以对访问控制列表进行查询、添加、更新和删除的操作,是开发人员最常直接使用的类。该类的构造方法需要 3 个参数,分别是 javax.sql.DataSource表示的数据源、org.springframework.security.acls.jdbc.LookupStrategy表示的数据库的查询策略和org.springframework.security.acls.model.AclCache表示的访问控制列表缓存。数据源可以使用第一个示例应用中已有的数据源。查询策略可以使用默认的实现 org.springframework.security.acls.jdbc.BasicLookupStrategy。缓存可以使用基于 EhCache 的缓存实现 org.springframework.security.acls.domain.EhCacheBasedAclCache代码清单 8中给出了相关代码。

清单 8. 使用 JDBC 的访问控制列表服务基本配置
 <bean id="aclService"
    class="org.springframework.security.acls.jdbc.JdbcMutableAclService"> 
    <constructor-arg ref="dataSource" /> 
    <constructor-arg ref="lookupStrategy" /> 
    <constructor-arg ref="aclCache" /> 
    <property name="classIdentityQuery" value="values IDENTITY_VAL_LOCAL()"/> 
    <property name="sidIdentityQuery" value="values IDENTITY_VAL_LOCAL()"/> 	
 </bean>

如 代码清单 8所示,需要注意的是 org.springframework.security.acls.jdbc.JdbcMutableAclService的属性classIdentityQuery和 sidIdentityQuery。Spring Security 的默认数据库模式使用了自动增长的列作为主键。而在实现中,需要能够获取到新插入的列的 ID。因此需要与数据库实现相关的 SQL 查询语言来获取到这个 ID。Spring Security 默认使用的 HSQLDB,因此这两个属性的默认值是 HSQLDB 支持的 call identity()。如果使用的数据库不是 HSQLDB 的话,则需要根据数据库实现来设置这两个属性的值。第一个示例应用使用的是 Apache Derby 数据库,因此这两个属性的值是 values IDENTITY_VAL_LOCAL()。对于 MySQL 来说,这个值是select @@identity代码清单 9给出了使用 org.springframework.security.acls.jdbc.JdbcMutableAclService来管理访问控制列表的 Java 代码。

清单 9. 使用访问控制列表服务
 public void createNewReport(String title, String content) throws ServiceException { 
    final Report report = new Report(); 
    report.setTitle(title); 
    report.setContent(content); 
		
    transactionTemplate.execute(new TransactionCallback<Object>() { 
        public Object doInTransaction(TransactionStatus status) { 
            reportDao.create(report); 
            addPermission(report.getId(), new PrincipalSid(getUsername()), 
                BasePermission.ADMINISTRATION); 
            return null; 
        } 
    }); 
 } 
	
 public void grantRead(final String username, final Long reportId) { 
    transactionTemplate.execute(new TransactionCallback<Object>() { 
        public Object doInTransaction(TransactionStatus status) { 
            addPermission(reportId, new PrincipalSid(username), BasePermission.READ); 
            return null; 
        } 
    }); 
 } 

 private void addPermission(Long reportId, Sid recipient, Permission permission) { 
    MutableAcl acl; 
    ObjectIdentity oid = new ObjectIdentityImpl(Report.class, reportId); 

    try { 
        acl = (MutableAcl) mutableAclService.readAclById(oid); 
    } catch (NotFoundException nfe) { 
        acl = mutableAclService.createAcl(oid); 
    } 

    acl.insertAce(acl.getEntries().size(), permission, recipient, true); 
    mutableAclService.updateAcl(acl); 
 }

代码清单 9中的 addPermission(Long reportId, Sid recipient, Permission permission)方法用来为某个报表添加访问控制权限,参数 reportId表示的是报表的 ID,用来标识一个报表;recipient表示的是需要授权的用户;permission表示的是授予的权限。createNewReport()方法用来创建一个报表,同时给创建报表的用户授予管理权限(BasePermission.ADMINISTRATION)。grantRead()方法用来给某个用户对某个报表授予读权限(BasePermission.READ)。这里需要注意的是,对访问控制列表的操作都需要在一个事务中进行处理。利用 Spring 提供的事务模板(org.springframework.transaction.support.TransactionTemplate)就可以很好的处理事务。对于权限,Spring Security 提供了 4 种基本的权限:读、写、删除和管理。开发人员可以在这基础上定义自己的权限。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值