有哪位大侠使用过spring security acl啊,我对这个搞的很困惑,有没有好的资料啊分享下。

解决方案 »

  1.   

    ACL即访问控制列表(Access Controller List),它是用来做细粒度权限控制所用的一种权限模型。对ACL最简单的描述就是两个业务员,每个人只能查看操作自己签的合同,而不能看到对方的合同信息。
    下面我们会介绍Spring Security中是如何实现ACL的。
    23.1. 准备数据库和aclServiceACL所需的四张表,表结构见附录:附录 E, 数据库表结构。
    然后我们需要配置aclService,它负责与数据库进行交互。
    23.1.1. 为acl配置cache默认使用ehcache,spring security提供了一些默认的实现类。
    <bean id="aclCache" class="org.springframework.security.acls.jdbc.EhCacheBasedAclCache">
        <constructor-arg ref="aclEhCache"/>
    </bean>
    <bean id="aclEhCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheName" value="aclCache"/>
    </bean>
                在ehcache.xml中配置对应的aclCache缓存策略。
    <cache
        name="aclCache"
        maxElementsInMemory="1000"
        eternal="false"
        timeToIdleSeconds="600"
        timeToLiveSeconds="3600"
        overflowToDisk="true"
    />
                23.1.2. 配置lookupStrategy简单来说,lookupStrategy的作用就是从数据库中读取信息,把这些信息提供给aclService使用,所以我们要为它配置一个dataSource,配置中还可以看到一个aclCache,这就是上面我们配置的缓存,它会把资源最大限度的利用起来。
    <bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
        <constructor-arg ref="dataSource"/>
        <constructor-arg ref="aclCache"/>
        <constructor-arg>
            <bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
                <constructor-arg>
                    <list>
                        <ref local="adminRole"/>
                        <ref local="adminRole"/>
                        <ref local="adminRole"/>
                    </list>
                </constructor-arg>
            </bean>
        </constructor-arg>
        <constructor-arg>
            <bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
        </constructor-arg>
    </bean>
    <bean id="adminRole" class="org.springframework.security.GrantedAuthorityImpl">
        <constructor-arg value="ROLE_ADMIN"/>
    </bean>
                中间一部分可能会让人感到困惑,为何一次定义了三个adminRole呢?这是因为一旦acl信息被保存到数据库中,无论是修改它的从属者,还是变更授权,抑或是修改其他的ace信息,都需要控制操作者的权限,这里配置的三个权限将对应于上述的三种修改操作,我们把它配置成,只有ROLE_ADMIN才能执行这三种修改操作。
    23.1.3. 配置aclService当我们已经拥有了dataSource, lookupStrategy和aclCache的时候,就可以用它们来组装aclService了,之后所有的acl操作都是基于aclService展开的。
    <bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
        <constructor-arg ref="dataSource"/>
        <constructor-arg ref="lookupStrategy"/>
        <constructor-arg ref="aclCache"/>
    </bean>
                23.2. 使用aclService管理acl信息当我们添加了一条信息,要在acl中记录这条信息的ID,所有者,以及对应的授权信息。下列代码在添加信息后执行,用于添加对应的acl信息。
    ObjectIdentity oid = new ObjectIdentityImpl(Message.class, message.getId());
    MutableAcl acl = mutableAclService.createAcl(oid);
    acl.insertAce(0, BasePermission.ADMINISTRATION,
        new PrincipalSid(owner), true);
    acl.insertAce(1, BasePermission.DELETE,
        new GrantedAuthoritySid("ROLE_ADMIN"), true);
    acl.insertAce(2, BasePermission.READ,
        new GrantedAuthoritySid("ROLE_USER"), true);
    mutableAclService.updateAcl(acl);
            第一步,根据class和id生成object的唯一标示。
    第二步,根据object的唯一标示,创建一个acl。
    第三步,为acl增加ace,这里我们让对象的所有者拥有对这个对象的“管理”权限,让“ROLE_ADMIN”拥有对这个对象的“删除”权限,让“ROLE_USER”拥有对这个对象的“读取”权限。
    最后,更新acl信息。
    当我们删除对象时,也要删除对应的acl信息。下列代码在删除信息后执行,用于删除对应的acl信息。
    ObjectIdentity oid = new ObjectIdentityImpl(Message.class, id);
    mutableAclService.deleteAcl(oid, false);
            使用class和id可以唯一标示一个对象,然后使用deleteAcl()方法将对象对应的acl信息删除。
    23.3. 使用acl控制delete操作上述代码中,除了对象的拥有者之外,我们还允许“ROLE_ADMIN”也可以删除对象,但是我们不会允许除此之外的其他用户拥有删除对象的权限,为了限制对象的删除操作,我们需要修改Spring Security的默认配置。
    首先要增加一个对delete操作起作用的表决器。
    <bean id="aclMessageDeleteVoter" class="org.springframework.security.vote.AclEntryVoter">
        <constructor-arg ref="aclService"/>
        <constructor-arg value="ACL_MESSAGE_DELETE"/>
        <constructor-arg>
            <list>
                <util:constant static-field="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
                <util:constant static-field="org.springframework.security.acls.domain.BasePermission.DELETE"/>
            </list>
        </constructor-arg>
        <property name="processDomainObjectClass" value="com.family168.springsecuritybook.ch12.Message"/>
    </bean>
            它只对Message这个类起作用,而且可以限制只有管理和删除权限的用户可以执行删除操作。
    然后要将这个表决器添加到AccessDecisionManager中。
    <bean id="aclAccessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
        <property name="decisionVoters">
            <list>
                <bean class="org.springframework.security.vote.RoleVoter"/>
                <ref local="aclMessageDeleteVoter"/>
            </list>
        </property>
    </bean>
            现在AccessDecisionManager中有两个表决器了,除了默认的RoleVoter之外,又多了一个我们刚刚添加的aclMessageDeleteVoter。
    现在可以把新的AccessDecisionManager赋予全局方法权限管理器了。
    <global-method-security secured-annotations="enabled"
        access-decision-manager-ref="aclAccessDecisionManager"/>
            然后我们就可以在MessageService.java中使用Secured注解,控制删除操作了。
    @Transactional
    @Secured("ACL_MESSAGE_DELETE")
    public void remove(Long id) {
        Message message = this.get(id);
        list.remove(message);
        ObjectIdentity oid = new ObjectIdentityImpl(Message.class, id);
        mutableAclService.deleteAcl(oid, false);
    }
            实际上,我们最好不要让没有权限的操作者看到remove这个链接,可以使用taglib隐藏当前用户无权看到的信息。
    <sec:accesscontrollist domainObject="${item}" hasPermission="8,16">
          |
          <a href="message.do?action=remove&id=${item.id}">Remove</a>
    </sec:accesscontrollist>
            8, 16是acl默认使用的掩码,8表示DELETE,16表示ADMINISTRATOR,当用户不具有这些权限的时候,他在页面上就看不到remove链接,也就无法执行操作了。
    这比让用户可以执行remove操作,然后跑出异常,警告访问被拒绝要友好得多。
    23.4. 控制用户可以看到哪些信息当用户无权查看一些信息时,我们需要配置afterInvocation,使用后置判断的方式,将用户无权查看的信息,从MessageService返回的结果集中过滤掉。
    后置判断有两种形式,一种用来控制单个对象,另一种可以过滤集合。
    <bean id="afterAclRead" class="org.springframework.security.afterinvocation.AclEntryAfterInvocationProvider">
        <sec:custom-after-invocation-provider/>
        <constructor-arg ref="aclService"/>
        <constructor-arg>
            <list>
                <util:constant static-field="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
                <util:constant static-field="org.springframework.security.acls.domain.BasePermission.READ"/>
            </list>
        </constructor-arg>
    </bean>
    <bean id="afterAclCollectionRead" class="org.springframework.security.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
        <sec:custom-after-invocation-provider/>
        <constructor-arg ref="aclService"/>
        <constructor-arg>
            <list>
                <util:constant static-field="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
                <util:constant static-field="org.springframework.security.acls.domain.BasePermission.READ"/>
            </list>
        </constructor-arg>
    </bean>
            afterAclRead可以控制单个对象是否可以显示,afterAclCollectionRead则用来过滤集合中哪些对象可以显示。[6]
    对这两个bean都是用了custom-after-invocation-provider标签,将它们加入的后置判断的行列,下面我们为MessageService.java中的对应方法添加Secured注解,之后它们就可以发挥效果了。
    @Secured({"ROLE_USER", "AFTER_ACL_READ"})
    public Message get(Long id) {
        for (Message message : list) {
            if (message.getId().equals(id)) {
                return message;
            }
        }
        return null;
    }
    @Secured({"ROLE_USER", "AFTER_ACL_COLLECTION_READ"})
    public List getAll() {
        return list;
    }
            以上就是Spring Security支持的ACL,我们只演示了DELETE一种情况,就已经编写了如此之多的xml配置文件,很难想象随着对象的增多,这个配置工作要扩展到什么程度,如何才能像之前配置user和resource时,将这些acl的信息都配置到database中呢?目前还是一个我们正在考虑的问题。
    --------------------------------------------------------------------------------[6] 这个地方会引发一个经典的问题,虎牙子,一般的思路是使用动态SQL的方式,在查询的时候就过滤掉无权显示的信息,但随着查询条件的复杂化,当出现SQL语句长度超过DBMS最大限制时,咱们就可以去撞墙了。
      

  2.   

    javax.servlet.ServletException: org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [call identity()]; nested exception is com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: PROCEDURE test.identity does not exist
    a.AccountServlet.doPost(AccountServlet.java:49)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
      

  3.   

    楼上的问题我刚查搜了一下,你用spring security2.0的话,使用这个aclService就不会报错了.
    <bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
        <constructor-arg ref="dataSource"/>
        <constructor-arg ref="lookupStrategy"/>
        <constructor-arg ref="aclCache"/>
        <property name="identityQuery" value="SELECT @@IDENTITY"/>
      </bean>
    如果是3.0的话,用这个
    <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="SELECT @@IDENTITY"/>
            <property name="sidIdentityQuery" value="SELECT @@IDENTITY"/>
        </bean>