`

acegi到spring security的转换方式

阅读更多

 

作者 Chris.Baker,发表于 2008/04/22 - 9:44am.

http://java.dzone.com/tips/pathway-acegi-spring-security-

以前它叫做spring的acegi安全框架,现在重新标识为spring security 2.0,它实现了简易配置的承诺,提高了开发者的生产力。 它已经是java平台上应用最广的安全框架了,在sourceforge上拥有250,000的下载量,Spring Security 2.0又提供了一系列的新功能。

本文主要介绍了如果把之前建立在acegi基础上的spring应用转换到spring security 2.0上。

25.1. Spring Security是什么

Spring Security是目前用于替换acegi的框架,它提供了一系列新的功能。

  • 大为简化了配置

  • 继承OpenID,标准单点登录

  • 支持windows NTLM,在windows合作网络上实现单点登录

  • 支持JSR 250("EJB 3")的安全注解

  • 支持AspectJ切点表达式语言

  • 全面支持REST Web请求授权

  • 长期要求的支持组,层级角色和用户管理API

  • 提升了功能,使用后台数据库的remember-me实现

  • 通过spring webflow 2.0对web状态和流转授权进行新的支持

  • 通过Spring Web Services 1.5加强对WSS(原来的WS-Security)的支持

  • 整个更多的……

25.2. 目标

目前,我工作在一个spring的web应用上,使用acegi控制对资源的访问权限。 用户信息保存在数据库中,我们配置acegi使用了基于JDBC的UserDetails服务。 同样的,我们所有的web资源都保存在数据库里,acegi配置成使用自定义的AbstractFilterInvocationDefinitionSource,对每个请求检测授权细节。

随着Spring Security 2.0的发布,我想看看是不是可以替换acegi,但还要保持当前的功能,使用数据库作为我们验证和授权的数据源,而不是xml配置文件(大多数演示程序里使用的都是xml)。

这里是我采取的步骤……

25.3. 步骤

  1. 第一步(也是最重要的)是下载新的Spring Security 2.0框架,并确保jar文件放到正确的位置(/WEB-INF/lib/)。

    Spring Security 2.0下载包里包含22个jar文件。我不需要把它们全用上(尤其是那些sources包)。在这次练习中我仅仅包含了以下几个:

    • 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. 在web.xml文件里配置一个DelegatingFilterProxy

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
                    
  3. Spring Security 2.0的配置比acegi简单太多了,所以我没有在以前acegi配置文件的基础上进行修改,我发现从一个空白文件开始更简单。如果你想修改你以前的配置文件,我确定你删除的行数比添加的行数还要多。

    配置文件的第一部分是指定安全资源过滤器的细节,这让安全资源可以通过数据库读取,而不是在配置文件里保存信息。这里是一个你将在大多数例子中看到的代码。

    <http auto-config="true" access-denied-page="/403.jsp">
        <intercept-url pattern="/index.jsp" access="ROLE_ADMINISTRATOR,ROLE_USER"/>
        <intercept-url pattern="/securePage.jsp" access="ROLE_ADMINISTRATOR"/>
        <intercept-url pattern="/**" access="ROLE_ANONYMOUS" />
    </http>
                    

    使用这些内容进行替换:

    <authentication-manager alias="authenticationManager"/>
    
    <beans:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
        <beans:property name="allowIfAllAbstainDecisions" value="false"/>
        <beans:property name="decisionVoters">
            <beans:list>
                <beans:bean class="org.springframework.security.vote.RoleVoter"/>
                <beans:bean class="org.springframework.security.vote.AuthenticatedVoter"/>
            </beans:list>
        </beans:property>
    </beans:bean>
    
    <beans:bean id="filterInvocationInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
    <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="org.security.SecureFilter.MySecureResourceFilter" />
    
    <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>
                    

    这段配置的主要部分secureResourceFilter,这是一个实现了FilterInvocationDefinitionSource的类,它在Spring Security需要对请求页面检测权限的时候调用。这里是MySecureResouceFilter的代码:

    package org.security.SecureFilter;
    
    import java.util.Collection;
    import java.util.List;
    
    import org.springframework.security.ConfigAttributeDefinition;
    import org.springframework.security.ConfigAttributeEditor;
    import org.springframework.security.intercept.web.FilterInvocation;
    import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
    
    
    public class MySecureResourceFilter implements FilterInvocationDefinitionSource {
    
        public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {
    
            FilterInvocation filterInvocation = (FilterInvocation) filter;
    
            String url = filterInvocation.getRequestUrl();
    
            // create a resource object that represents this Url object
            Resource resource = new Resource(url);
    
            if (resource == null) return null;
            else{
                ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
                // get the Roles that can access this Url
                List<Role> roles = resource.getRoles();
                StringBuffer rolesList = new StringBuffer();
                for (Role role : roles){
                    rolesList.append(role.getName());
                    rolesList.append(",");
                }
                // don't want to end with a "," so remove the last ","
                if (rolesList.length() > 0)
                    rolesList.replace(rolesList.length()-1, rolesList.length()+1, "");
                configAttrEditor.setAsText(rolesList.toString());
                return (ConfigAttributeDefinition) configAttrEditor.getValue();
            }
        }
    
        public Collection getConfigAttributeDefinitions() {
            return null;
        }
    
        public boolean supports(Class arg0) {
            return true;
        }
    
    }
                    

    getAttributes()方法返回权限的名称(我称之为角色),它们控制当前url的访问权限。

  4. 好了,现在我们需要安装信息数据库,下一步是让Spring Security从数据库中读取用户信息。这个Spring Security 2.0的例子告诉你如何从下面这样的配置文件里获得用户和权限的列表:

    <authentication-provider>
        <user-service>
        <user name="rod" password="password" authorities="ROLE_SUPERVISOR, ROLE_USER" />
        <user name="dianne" password="password" authorities="ROLE_USER,ROLE_TELLER" />
        <user name="scott" password="password" authorities="ROLE_USER" />
        <user name="peter" password="password" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
                    

    你可以把这些例子的配置替换掉,这样你可以像这样从数据库中直接读取用户信息:

    <authentication-provider>
        <jdbc-user-service data-source-ref="dataSource" />
    </authentication-provider>
                    

    这里有一种非常快速容易的方法来配置安全数据库,意思是你需要使用默认的数据库表结构。默认情况下,<jdbc-user-service>需要下面的几个表:user,authorities,groups,group_members和group_authorities。

    我的情况下,我的安全数据库表无法这样工作,它和<jdbc-user-service>要求的不同,所以我需要修改<authentication-provider>:

    <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, R.name as 'authority' FROM User U JOIN Authority A ON u.id = A.userId JOIN Role R ON R.id = A.roleId WHERE U.username=?"/>
    </authentication-provider>
                    

    通过添加users-by-username-query和authorities-by-username-query属性,你可以使用你自己的SQL覆盖默认的SQL语句。就像在acegi中一样,你必须确保你的SQL语句返回的列与Spring Security所期待的一样。这里有另一个group-authorities-by-username-query属性,我在这里没有用到,所以也没有出现在这里例子中,不过它的用法与其他两个SQl语句的方法完全一致。

    <jdbc-user-service>的这些功能大概是在上个月才加入的,在Spring Security之前版本中是无法使用的。幸运的是它已经被加入到Spring Security中了,这让我们的工作更加简单。你可以通过 这里这里获取信息。

    dataSource bean中指示的是链接数据库的信息,它没有包含在我的配置文件中,因为它并不只用在安全中。这里是一个dataSource的例子,如果谁不熟悉可以参考一下:

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost/db_name?useUnicode=true&characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="pwd"/>
    </bean>
                    
  5. 这就是Spring Security的所有配置文件。我最后一项任务是修改以前的登陆页面。在acegi中你可以创建自己的登陆<form>,向正确的URL发送正确命名的HTML输入元素。现在你也可以在Spring Security 2.0里这样做,只是一些名称发生了改变。你可以像以前一样使用用户名j_username和密码j_password。

    <input type="text" name="j_username" id="j_username"/>
    <input type="password" name="j_password" id="j_password"/>
                    

    但是你必须把<form>中的action指向j_spring_security_check而不是j_acegi_security_check。

    <form method="post" id="loginForm" action="<c:url value='j_spring_security_check'/>"
                    

    在你的应用中有一些地方,用户可以进行注销,这是一个链接把注销请求发送给安全框架,这样它就可以进行相应的处理。需要把它从j_acegi_logout改成j_spring_security_logout。

    <a href='<c:url value="j_spring_security_logout"/>'>Logout</a>
                    

25.4. 总结

这个简短的指南,包含了如何配置Spring Security 2.0使用数据库中的资源,它并没有演示Spring Security 2.0中的新特性,然而我想它可以演示一些非常常用的框架功能,我希望你们觉得它有用。

Spring Security 2.0与acegi相比的好处之一是配置文件非常简单,这在我比较老acegi配置文件(172行)和新配置文件(42行)的时候,清楚的显示出路爱。

这里是我完整的securityContext.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans,http://www.springframework.org/schema/beans/spring-beans-2.0.xsd,http://www.springframework.org/schema/security,http://www.springframework.org/schema/security/spring-security-2.0.xsd">

	<authentication-manager alias="authenticationManager"/>

	<beans:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
		<beans:property name="allowIfAllAbstainDecisions" value="false"/>
		<beans:property name="decisionVoters">
			<beans:list>
				<beans:bean class="org.springframework.security.vote.RoleVoter"/>
				<beans:bean class="org.springframework.security.vote.AuthenticatedVoter"/>
			</beans:list>
		</beans:property>
	</beans:bean>

	<beans:bean id="filterInvocationInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
		<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="org.security.SecureFilter.MySecureResourceFilter" />

	<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="org.springframework.security.event.authentication.LoggerListener"/>

	<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, R.name as 'authority' FROM User U JOIN Authority A ON u.id = A.userId JOIN Role R ON R.id = A.roleId WHERE U.username=?" />
	</authentication-provider>
</beans:beans>
        

就像在第一步时提到到,下载Spring Security是最重要的步骤。从那里开始就可以一帆风顺了。

分享到:
评论

相关推荐

    Spring Security-3.0.1中文官方文档(翻译版)

    16. acegi 到spring security 的转换方式 16.1. Spring Security 是什么 16.2. 目标 16.3. 步骤 16.4. 总结 V. 高级话题 17. 领域对象安全(ACLs) 17.1. 概述 17.2. 关键概念 17.3. 开始 18. 预...

    Spring Security 中文教程.pdf

    16. acegi到spring security的转换方式 16.1. Spring Security是什么 16.2. 目标 16.3. 步骤 16.4. 总结 V. 高级话题 17. 领域对象安全(ACLs) 17.1. 概述 17.2. 关键概念 17.3. 开始 18. 预认证...

    spring web flow demo

    除了 End State 外,其他 state 都可以转换到别的 state ,一般通过在 state 中 定义 transition 来实现到其他 state 的转换,转换的发生一般由事件( event )来触发。 什么情况下可以使用 Spring Web Flow? 前面...

    java开源包1

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包11

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包2

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包3

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包6

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包5

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包10

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包4

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包8

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包7

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包9

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包101

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    Java资源包01

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    JAVA上百实例源码以及开源项目

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

    JAVA上百实例源码以及开源项目源代码

     通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 ...

Global site tag (gtag.js) - Google Analytics