Pathway from ACEGI to Spring Security 2.0

Formerly called ACEGI Security for Spring, the re-branded Spring Security 2.0 has delivered on its promises of making it simpler to use and improving developer productivity. Already considered as the Java platform’s most widely used enterprise security framework with over 250,000 downloads from SourceForge, Spring Security 2.0 provides a host of new features.

This article outlines how to convert your existing ACEGI based Spring application to use Spring Security 2.0.

What is Spring Security 2.0

Spring Security 2.0 has recently been released as a replacement to ACEGI and it provides a host of new security features:

  • Substantially simplified configuration.

  • OpenID integration, single sign on standard.

  • Windows NTLM support, single sign on against Windows corporate networks.

  • Support for JSR 250 (“EJB 3”) security annotations.

  • AspectJ pointcut expression language support.

  • Comprehensive support for RESTful web request authorization.

  • Long-requested support for groups, hierarchical roles and a user management API.

  • An improved, database-backed “remember me” implementation.

  • New support for web state and flow transition authorization through the Spring Web Flow 2.0 release.

  • Enhanced WSS (formerly WS-Security) support through the Spring Web Services 1.5 release.

  • A whole lot more…


Currently I work on a Spring web application that uses ACEGI to control access to the secure resources. Users are stored in a database and as such we have configured ACEGI to use a JDBC based UserDetails Service. Likewise, all of our web resources are stored in the database and ACEGI is configure to use a custom AbstractFilterInvocationDefinitionSource to check authorization details for each request.
With the release of Spring Security 2.0 I would like to see if I can replace ACEGI and keep the current ability to use the database as our source of authentication and authorization instead of the XML configuration files (as most examples demonstrate).

Here are the steps that I took…


  1. The first (and trickiest) step was to download the new Spring Security 2.0 Framework and make sure that the jar files are deployed to the correct location. (/WEB-INF/lib/)
    There are 22 jar files that come with the Spring Security 2.0 download. I did not need to use all of them (especially not the *sources packages). For this exercise I only had to include:

    • spring-security-acl-2.0.0.jar

    • spring-security-core-2.0.0.jar

    • spring-security-core-tiger-2.0.0.jar

    • spring-security-taglibs-2.0.0.jar

  2. Configure a DelegatingFilterProxy in the web.xml file.

    1. <filter>  

    2.     <filter-name>springSecurityFilterChain</filter-name>  

    3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  

    4. </filter>  

    5. <filter-mapping>  

    6.     <filter-name>springSecurityFilterChain</filter-name>  

    7.     <url-pattern>/*</url-pattern>  

    8. </filter-mapping>  

  3. Configuration of Spring Security 2.0 is far more concise than ACEGI, so instead of changing my current ACEGI based configuration file, I found it easier to start from a empty file. If you do want to change your existing configuration file, I am sure that you will be deleting more lines than adding.

    The first part of the configuration is to specifiy the details for the secure resource filter, this is to allow secure resources to be read from the database and not from the actual configuration file. This is an example of what you will see in most of the examples:

    1. <http auto-config=“true” access-denied-page=“/403.jsp”>  

    2.     <intercept-url pattern=“/index.jsp” access=“ROLE_ADMINISTRATOR,ROLE_USER”/>  

    3.     <intercept-url pattern=“/securePage.jsp” access=“ROLE_ADMINISTRATOR”/>  

    4.     <intercept-url pattern=“/**” access=“ROLE_ANONYMOUS” />  

    5. </http>  
    Replace this with:

    1. <authentication-manager alias=“authenticationManager”/>  


    3. <beans:bean id=“accessDecisionManager” class=“”>  

    4.     <beans:property name=“allowIfAllAbstainDecisions” value=“false”/>  

    5.     <beans:property name=“decisionVoters”>  

    6.         <beans:list>  

    7.             <beans:bean class=“”/>  

    8.             <beans:bean class=“”/>  

    9.         </beans:list>  

    10.     </beans:property>  

    11. </beans:bean>  


    13. <beans:bean id=“filterInvocationInterceptor” class=“”>  

    14. <beans:property name=“authenticationManager” ref=“authenticationManager”/>  

    15.     <beans:property name=“accessDecisionManager” ref=“accessDecisionManager”/>  

    16.     <beans:property name=“objectDefinitionSource” ref=“secureResourceFilter” />  

    17. </beans:bean>  


    19. <beans:bean id=“secureResourceFilter” class=“” />  


    21. <http auto-config=“true” access-denied-page=“/403.jsp”>  

    22.     <concurrent-session-control max-sessions=“1” exception-if-maximum-exceeded=“true” />  

    23.     <form-login login-page=“/login.jsp” authentication-failure-url=“/login.jsp” default-target-url=“/index.jsp” />  

    24.     <logout logout-success-url=“/login.jsp”/>  

    25.  </http>  

    The main part of this piece of configuration is the secureResourceFilter, this is a class that implementsFilterInvocationDefinitionSource and is called when Spring Security needs to check the Authorities for a requested page.
    Here is the code for MySecureResourceFilter:

    1. package;  


    3. import java.util.Collection;  

    4. import java.util.List;  


    6. import;  

    7. import;  

    8. import;  

    9. import;  



    12. public class MySecureResourceFilter implements FilterInvocationDefinitionSource {  


    14.     public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {  


    16.         FilterInvocation filterInvocation = (FilterInvocation) filter;  


    18.         String url = filterInvocation.getRequestUrl();  


    20.         // create a resource object that represents this Url object  

    21.         Resource resource = new Resource(url);  


    23.         if (resource == nullreturn null;  

    24.         else{  

    25.             ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();  

    26.             // get the Roles that can access this Url  

    27.             List<Role> roles = resource.getRoles();  

    28.             StringBuffer rolesList = new StringBuffer();  

    29.             for (Role role : roles){  

    30.                 rolesList.append(role.getName());  

    31.                 rolesList.append(“,”);  

    32.             }  

    33.             // don’t want to end with a “,” so remove the last “,”  

    34.             if (rolesList.length() > 0)  

    35.                 rolesList.replace(rolesList.length()-1, rolesList.length()+1“”);  

    36.             configAttrEditor.setAsText(rolesList.toString());  

    37.             return (ConfigAttributeDefinition) configAttrEditor.getValue();  

    38.         }         

    39.     }  


    41.     public Collection getConfigAttributeDefinitions() {  

    42.         return null;  

    43.     }  


    45.     public boolean supports(Class arg0) {  

    46.         return true;  

    47.     }  


    49. }  
    This getAttributes() method above essentially returns the name of Authorities (which I call Roles) that are allowed access to the current Url.

  4. OK, so now we have setup the database based resources and now the next step is to get Spring Security to read the user details from the database. The examples that come with Spring Security 2.0 shows you how to keep a list of users and authorities in the configuration file like this:

    1. <authentication-provider>  

    2.     <user-service>  

    3.     <user name=“rod” password=“password” authorities=“ROLE_SUPERVISOR, ROLE_USER” />  

    4.     <user name=“dianne” password=“password” authorities=“ROLE_USER,ROLE_TELLER” />  

    5.     <user name=“scott” password=“password” authorities=“ROLE_USER” />  

    6.     <user name=“peter” password=“password” authorities=“ROLE_USER” />  

    7.     </user-service>  

    8. </authentication-provider>  
    You could replace these examples with this configuration so that you can read the user details straight from the database like this:

    1. <authentication-provider>  

    2.     <jdbc-user-service data-source-ref=“dataSource” />  

    3. </authentication-provider>  
    While this is a very fast and easy way to configure database based security it does mean that you have to conform to a default databases schema. By default, the <jdbc-user-service> requires the following tables: user, authorities, groups, group_members and group_authorities.
    In my case this was not going to work as my security schema it not the same as what the <jdbc-user-service>requires, so I was forced to change the <authentication-provider>:

    1. <authentication-provider>  

    2.     <jdbc-user-service data-source-ref=“dataSource”  

    3.     users-by-username-query=“SELECT U.username, U.password, U.accountEnabled AS ‘enabled’ FROM User U where U.username=?”  

    4.     authorities-by-username-query=“SELECT U.username, as ‘authority’ FROM User U JOIN Authority A ON = A.userId JOIN Role R ON = A.roleId WHERE U.username=?”/>  

    5. </authentication-provider>  
    By adding the users-by-username-query and authorities-by-username-query properties you are able to override the default SQL statements with your own. As in ACEGI security you must make sure that the columns that your SQL statement returns is the same as what Spring Security expects. There is a another property group-authorities-by-username-query which I am not using and have therefore left it out of this example, but it works in exactly the same manner as the other two SQL statements.

    This feature of the <jdbc-user-service> has only been included in the past month or so and was not available in the pre-release versions of Spring Security. Luckily it has been added as it does make life a lot easier. You can read about this here and here.

    The dataSource bean instructs which database to connect to, it is not included in my configuration file as it’s not specific to security. Here is an example of a dataSource bean for those who are not sure:

    1. <bean id=“dataSource” class=“org.springframework.jdbc.datasource.DriverManagerDataSource”>  

    2.     <property name=“driverClassName” value=“com.mysql.jdbc.Driver”/>  

    3.     <property name=“url” value=“jdbc:mysql://localhost/db_name?useUnicode=true&characterEncoding=utf-8”/>  

    4.     <property name=“username” value=“root”/>  

    5.     <property name=“password” value=“pwd”/>  

    6. </bean>  

  5. And that is all for the configuration of Spring Security. My last task was to change my current logon screen. In ACEGI you could create your own logon <form> by making sure that you POSTED the correctly named HTML input elements to the correct URL. While you can still do this in Spring Security 2.0, some of the names have changed.
    You can still call your username field j_username and your password field j_password as before.

    1. <input type=“text” name=“j_username” id=“j_username”/>  

    2. <input type=“password” name=“j_password” id=“j_password”/>  
    However you must set the action property of your <form> to point to j_spring_security_check and notj_acegi_security_check.

    1. <form method=“post” id=“loginForm” action=“<c:url value=’j_spring_security_check’/>”  
    There are a few places in our application where the user can logout, this is a link that redirects the logout request to the security framework so that it can be handled accordingly. This needs to be changed from j_acegi_logout toj_spring_security_logout.

    1. <a href=‘<c:url value=”j_spring_security_logout”/>’>Logout</a>  


This short guide on how to configure Spring Security 2.0 with access to resources stored in a database does not come close to illustrating the host of new features that are available in Spring Security 2.0, however I think that it does show some of the most commonly used abilities of the framework and I hope that you will find it useful.

One of the benefits of Spring Security 2.0 over ACEGI is the ability to write more consice configuration files, this is clearly shown when I compare my old ACEGI configration (172 lines) file to my new one (42 lines).
Here is my complete securityContext.xml file:

  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans:beans xmlns=“”   

  3. xmlns:beans=“”   

  4. xmlns:xsi=“”   

  5. xsi:schemaLocation=“,,,”> <authentication-manager alias=“authenticationManager”/>  <beans:bean id=“accessDecisionManager” class=“”> <beans:property name=“allowIfAllAbstainDecisions” value=“false”/> <beans:property name=“decisionVoters”> <beans:list> <beans:bean class=“”/> <beans:bean class=“”/> </beans:list> </beans:property> </beans:bean> <beans:bean id=“filterInvocationInterceptor” class=“”> <beans:property name=“authenticationManager” ref=“authenticationManager”/> <beans:property name=“accessDecisionManager” ref=“accessDecisionManager”/> <beans:property name=“objectDefinitionSource” ref=“secureResourceFilter” /> </beans:bean>  <beans:bean id=“secureResourceFilter” class=“” /> <http auto-config=“true” access-denied-page=“/403.jsp”>  <concurrent-session-control max-sessions=“1” exception-if-maximum-exceeded=“true” /> <form-login login-page=“/login.jsp” authentication-failure-url=“/login.jsp” default-target-url=“/index.jsp” /> <logout logout-success-url=“/login.jsp”/> </http>  <beans:bean id=“loggerListener” class=“”/>  <authentication-provider> <jdbc-user-service data-source-ref=“dataSource” users-by-username-query=“SELECT U.username, U.password, U.accountEnabled AS ‘enabled’ FROM User U where U.username=?” authorities-by-username-query=“SELECT U.username, as ‘authority’ FROM User U JOIN Authority A ON = A.userId JOIN Role R ON = A.roleId WHERE U.username=?” /> </authentication-provider> </beans:beans>  

As I said in step 1, downloading Spring Security was the trickiest step of all. From there on it was plain sailing…


下篇地址:Spring中基于aop命名空间的AOP 二(声明一个切面、切入点和通知)

    在某些时候,我们工程中使用的JDK 不一定就是1.5 以上,也就是说可能不支持Annotation 注解,这时自然也就不能使用@AspectJ 注解驱动的AOP 了,那么如果我们仍然想使用AspectJ 灵活的切入点表达式,那么该如何呢?Spring 为我们提供了基于xml schematic 的aop 命名空间,它的使用方式和@AspectJ 注解类似,不同的是配置信息从注解中转移到了Spring 配置文件中。在这里,我们将详细介绍如何使用Spring 提供的<aop:config/> 标签来配置Spring AOP 。

1 、一点准备工作和一个例子

    使用<aop:config/> 标签,需要给Spring 配置文件中引入基于xml schema 的Spring AOP 命名空间。完成后的Spring 配置文件如下(在该节,所有例程的配置文件中添加了Spring AOP 命名空间,除非特殊情况外,为了节约空间,这部分将在给出的代码中省略),粗体内容即为我们需要添加的内容:

  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans xmlns=“”  

  3.         xmlns:xsi=“”  

  4.         xmlns:aop=“”  

  5.         xsi:schemaLocation=”   



  8.      >  

  9. ………… Spring配置信息   

  10. </beans>  


   下面有一个例程来直观的展示如何使用<aop:config/>标签来配置Spring AOP(完整代码见例程4.15)。在例子中,我们使用<aop:config/>配置一个切面并拦截目标对象Peoples的SayHello()方法,在它执行前输出提示信息。
首先创建工程AOP_Test4.15,添加Spring IoC和Spring AOP库后,创建aop.test包,新建目标类People,代码如下:

  1. package aop.test;   


  3. /**  

  4.  * 该类将作为目标对象对应的类。  

  5.  * @author zhangyong  

  6.  * */  

  7. public class People{   


  9.         public String SayHello(String str){   

  10.                 System.out.println(this.getClass().getName()+ “说:”+str);   

  11.                 return str;   

  12.         }   

  13. }   

    修改Spring xml配置文件,将该类注册为一个受管Bean:

  1. <bean id=“TestBean” class=“aop.test.People” />  

    创建含有main()方法的测试类TestMain,从Spring IoC容器中获取Peoples对象,并调用其SayHello()方法,代码如下:

  1. package aop.test;   


  3. // import省略   

  4. public class TestMain {   

  5.         public static void main(String[] args) {   

  6.                 // 实例化Spring IoC容器   

  7.                 ApplicationContext ac = new ClassPathXmlApplicationContext(   

  8.                                 “applicationContext.xml”);   

  9.                 // 获取受管Bean的实例   

  10.                 People p = (People) ac.getBean(“TestBean”);   

  11.                 p.SayHello(“传入的参数值”);   

  12.         }   

  13. }   


  1. package aop.test;   


  3. import org.aspectj.lang.JoinPoint;   


  5. public class MyAspect {   


  7.         public void beforeAdvice(JoinPoint point) {   

  8.             System.out.println(“前置通知被触发:” +    

  9.                                 point.getTarget().getClass().getName()+    

  10.                                 “将要” + point.getSignature().getName());   

  11.         }   

  12. }   

    修改xml配置文件,为其添加aop命名空间,并把MyAspect注册为一个受管Bean,作为我们下面定义切面的backing bean。代码如下:

  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans xmlns=“”  

  3.         xmlns:xsi=“”  

  4.         xmlns:aop=“”  

  5.         xsi:schemaLocation=”   





  10.         <bean id=“MyAspect” class=“aop.test.MyAspect” />  

  11.         <bean id=“TestBean” class=“aop.test.People” />  


  13.         <aop:config proxy-target-class=“true”>  

  14.                 <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  15.                         <aop:pointcut id=“testPointcut”  

  16.                                 expression=“execution(* aop..*(..))” />  

  17.                         <aop:before pointcut-ref=“testPointcut”  

  18.                                 method=“beforeAdvice” />  

  19.                 </aop:aspect>  

  20.         </aop:config>  

  21. </beans>  





      在基于AOP命名空间的Spring AOP中,要声明一个切面,需要使用<aop:config/>的子标签<aop:aspect>。<aop:aspect>标签有一个ref属性必须被赋值,它用于指定和该切面关联的受管Bean(backing bean,以后我们都将使用Backing Bean来称呼这样的Bean)。正如下例所示,该Bean对应的java类是一个普通的java类,在该类中定义了切面的通知方法。此外,<aop:aspect>标签还有两个可选的order属性和id属性,order属性用于指定该切面的加载顺序,id属性用于标识该切面。范例如下:

  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans ……>  

  3.         <bean id=“MyAspect” class=“aop.test.MyAspect” />  

  4.         <aop:config proxy-target-class=“true”>  

  5.                 <aop:aspect ref=“MyAspect” order=“1” id=“TestAspectName”>  

  6.                         ……切面其他配置   

  7.                 </aop:aspect>  

  8.         </aop:config>  

  9. ……其他配置   

  10. </beans>    



  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans ……>  

  3.     <bean id=“MyAspect” class=“aop.test.MyAspect”/>  

  4.     <aop:config proxy-target-class=“true”>  

  5.         <aop:aspect ref=“MyAspect” order=“1” id=”TestAspectName”>  

  6.               <aop:pointcut id=“test”  

  7.                 expression=“execution(* aop.test.TestBean.*(..))”/>  

  8.               <aop:before pointcut=“aop.test.MyAspect.Pointcut1()”    

  9.                                method=“beforeAdvice” />  

  10.         </aop:aspect>  

  11.     </aop:config>  

  12. ……其他配置   

  13. </beans>  



  1. <aop:pointcut id=“test”   expression=“aop.test.MyAspect.Pointcut1()” />  



4、 声明一个通知







通过 id 引用已定义的切入点


指定通知对应的方法,该方法必须已在切面的 backing bean 中被声明




  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))”/>  

  4.     <aop:before pointcut-ref=“testPointcut” method=“beforeAdvice”/>  

  5. </aop:aspect>  


     2)、 后置通知

  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.     <aop:after  pointcut-ref=“testPointcut” method=“AfterAdvice”/>  

  5. </aop:aspect>  


     3)、 返回后通知

  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.     <aop:after-returning pointcut-ref=“testPointcut”  

  5.         method=“AfterReturnAdvice” returning=“reVlue” />  

  6. </aop:aspect>  


       4)、 异常通知
        声明一个异常通知使用<aop:after-throwing />标签,它有一个类似于throwing属性又来指定该通知匹配的异常类型。用法如下:

  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.      <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.      <aop:after-throwing pointcut-ref=“testPointcut”  

  5.         method=“afterThrowingAdvice” throwing=“throwable” />  

  6. </aop:aspect>  


      5)、 环绕通知

  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.         <aop:around pointcut-ref=“testPointcut” method=“aroundAdvice”/>  

  5. </aop:aspect>