摘 要: Spring框架是一个优秀的多层J2EE系统框架,Spring本身没有提供对系统的安全性支持。Acegi是基于Spring IOC 和 AOP机制实现的一个安全框架。本文讨论了Acegi安全框架中各部件之间的交互,并通过扩展Acegi数据库设计来实现基于Spring框架的应用的安全控制方法。
关键词: Spring ;Acegi ;认证; 受权
近年来,随着Internet技术的迅猛发展,计算机网络已深入到了人们的工作、学习和日常生活中,于是,怎么构建安全的web应用也成为了当前最热门的话题。Spring是一个基于IoC(Inversion of Control)和AOP(Aspect Oriented Programming)的构架多层J2EE应用系统的框架。Spring框架正在以其优良的特性吸引了越来越多的开发人员的关注,并在大量的系统开发中被使用。然而,现有的Spring框架本身并没有提供对系统安全性的支持,本文通过详情一种可用于Spring框架中的安全框架Acegi,并对在Spring框架中使用Acegi实现安全客户认证和资源受权控制进行了较深入的研究和扩展,同时给出了可行的处理方案。
Spring框架是由Open Source开发的一个优秀的多层J2EE系统框架,它为企业级应用提供了一个非常轻量级的处理方案,大大地降低了应用开发的难度与复杂度,提高了开发的速度。
Spring框架的核心是IoC和AOP。IoC是一种设计模式,即IoC模式。IoC模式进一步降低了类之间的耦合度,并且改变了传统的对象的创立方法,实现了一种配置式的对象管理方式,Spring框架中由IoC容器负责配置性的对象的管理。IoC模式极大的提高了系统开发与维护的灵活性。
AOP是一种编程模式,它是从系统的横切面关注问题。传统的面向对象编程OOP主要从系统的垂直切面对问题进行关注,对于系统的横切面关注很少,或者者说很难关注,这样当考虑到系统的安全性、日志、事务以及其余企业级服务时,OOP就无能为力了,只能在所有相关类中加入相似的系统服务级的代码。AOP为处理系统级服务问题提供了一种很好的方法。AOP将系统服务分解成方面看待,并为类提供一种公告式系统服务方式。Java类不需要知道日志服务的存在也不需要考虑相关的代码。所以,用AOP编写的应用程序是松耦合的,代码的复用性就提高了。
借助于Spring框架,开发者能够快速构建结构良好的WEB应用,但现有的Spring框架本身没有提供安全相关的处理方案。同样来自于Open Source 社区的Acegi安全框架为实现基于Spring框架的WEB应用的安全控制提供了一个很好的处理方案。Acegi本身就是利用Spring提供的IoC和AOP机制实现的一个安全框架,它将安全性服务作为J2EE平台中的系统级服务,以AOP Aspect形式发布。所以借助于Acegi安全框架,开发者能够在Spring使能应用中采用公告式方式实现安全控制。
Acegi安全框架主要由安全管理对象、阻拦器以及安全控制管理组件组成。安全管理对象是系统可以进行安全控制的实体,Acegi框架主要支持方法和URL请求两类安全管理对象;阻拦器是Acegi中的重要部件,用来实现安全控制请求的阻拦,针对不同的安全管理对象的安全控制请求使用不同的阻拦器进行阻拦;安全控制管理部件是实际实现各种安全控制的组件,对被阻拦器阻拦的请求进行安全管理与控制,主要组件包括实现客户身份认证的AuthenticationManager、实现客户受权的AccessDecisionManager 以及实现角色转换的RunAsManager。安全管理对象、阻拦器以及安全控制管理组件三者关系如图1所示。
首先,需要明确进行安全控制的对象,可为业务方法和URL资源。
其次,需要进一步明确,系统身份认证资料和资源受权信息的数据持久化形式。
在Acegi框架中支持多种安全信息的持久化方式,可以在配置文件中配置或者存放在关系数据库。因为在实际应用中,需求是经常发生变化的。所以,在配置文件中配置是满足不了实际应用需求的。然而,Acegi本身对权限表的设计非常简单,users表{username,password,enabled} 和authorities表{username,authority},这样简单的设计一定无法适用复杂的权限需求。为理解决权限管理的复杂性,在这里引入了role(角色)的概念,使得客户和权限分离,一个客户拥有多个角色,一个角色拥有多个相应的权限,这样就更灵活地支持安全策略。
同时,为了更好地配合Acegi安全框架,还引入resource(资源)的概念,资源可分为URL和FUNCTION(方法)两种,一个权限可以对应多个资源。具体的数据库设计见图2。
实现系统的安全控制,首先需要对系统的安全管理器和受权管理器进行配置,系统进行认证和受权需要获取安全信息,Acegi本身提供了对认证信息的获取机制,在实现认证与受权过程中,系统将主动根据配制信息和相应的信息解释安全信息的读取。图3给出了一个将客户安全信息存储在数据库中的认证管理器的配置示用意。
对应于图示的XML配置文件的代码如下:
/* 配置数据库datasource 和Acegi 的 jdbcDao */<bean id=”dataSource” class=”org.springframework.jdbc.datasource.DriverManagerDataSource”><property name=”driverClassName”><value>${jdbc.driverClassName}</value></property><property name=”url”><value>${jdbc.url}</value></property>
<property name=”username”><value>${jdbc.username}</value></property><property name=”password”><value>${jdbc.password}</value></property></bean><bean id=”jdbcDaoImpl” class=”org.acegisecurity. roviders. dao.jdbc.JdbcDaoImpl”><property name=”dataSource”><ref bean=”dataSource”/></property></bean>/*配置客户信息的加密算法*/<bean id=”passwordEncoder”Class=”org.acegisecurity.providers.encoding.Md5passwordEncoder”/>/*配置缓存有效时间*/<bean id=”userCache” class=”org.acegiSecurity. providers. dao.cache.EhCacheBasedUserCache”>…//这里对缓存有效时间进行设置</bean>/*配置daoAuthenticationProvider*/<bean id=”daoAuthenticationProvider” class=”org.acegisecurity.providers.dao.DaoAuthenticationProvider”><property name=”authenticationDao”><ref local=”JdbcDaoImpl”/></property><property name=”passwordEncoder”><ref local=” passwordEncoder”/></property><property name=”userCache”><ref local=” userCache”/></property></bean>/*配置认证管理器*/<bean id=”authenticationManager” class=”org.acegisecurity. providers.ProviderManager”><property name=”providers”><list><ref local=”daoAuthenticationProvider”/></list></property></bean>
受权管理器的配置方法与认证管理器的配置基本相似,这里不再探讨。
以上配置完成后,就需要配置安全阻拦器。不同的安全管理对象需要使用不同的安全阻拦器。对于方法级的安全认证需要使用的阻拦器为MethodSecurityInterceptor,而应用于URL资源的安全阻拦器为FilterSecurityInterceptor 。其中,MethodSecurityInterceptor阻拦器是借助于Spring Aop实现的,而FilterSecurityInterceptor阻拦器是借助于Servlet Filter 实现的。本文以URL资源请求的安全阻拦器为例说明配置情况。
因为URL资源请求安全阻拦是借助于过滤器进行的。因而首先要配置Acegi Servlet过滤器。过滤器相似于AOP Around装备,实现在web资源调用前后进行的少量操作6种过滤器,他们依次构成Servlet过滤器链,依次解决用户请求。需要注意的是过滤器配置的顺序是不能交换的,当不需要使用某个过滤器时,可直接将其删除和注释。过滤器在web.xml中配置形式为
<filter><filter-name>Acegi HTTP Request Security Filter</filter-name><filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class><init-param><param-name>targetClass</param-name><param-value>Org.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value></init-param></filter><filter-mapping><filter-name>Acigi HTTP Request Security Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
在spring applicationContext.xml文件中的配置形式为
<bean id=”securityEnforcementFilter” class=””><property name=”filterSecurityInterceptor”><ref bean=”filterInvocationInteceptor”/></property><property name=”authenticationEntryPoint”><ref bean=”authenticationProcessingFilterEntryPoint”/></property>
以上代码是SecurityEnforcementFilter的配置,该过滤器对客户能否有权访问web资源作出最后的决定。其它的过滤器的配置类同。
配置完过滤器后,需要对阻拦器FilterSecurityInterceptor进行配置,
<bean id=”filterInvocationInterceptor”Class=””><property name=”authenuserCacheticationManager”>1<property name=”accessDecisionManager”><property name=”objectDefinitionSource”><ref local="filterObjectDefinitionSource"/></property><bean id="filterObjectDefinitionSource"class="org.xiaohongli.acegi.db.DBFilterObjectDefinitionSource"><constructor-arg><refbean="jdbcTemplate"/> </constructor-arg></bean>
objectDefinitionSource属性定义了那些受保护的URL资源,其中引用了一个本地对象filterObjectDefinitionSource。 filterObjectDefinitionSource类从数据库中读取需要保护的URL安全信息,它扩展了PathBasedFilterInvocationDefinition Map类。
同样,实现了另外一个methodObjectDefinitionSource类从数据库中读取需要保护的FUNCTION资源,它扩展了MethodDefinitionMap类。限于篇幅,在这里就不列出具体实现的源代码。
<bean id="methodObjectDefinitionSource"class="org.xiaohongli.acegi.db.DBMethodObjectDefinitionSource"><constructor-arg><refbean="jdbcTemplate"/> </constructor-arg></bean>
因为Spring在越来越多的项目中的应用,因而基于Spring应用的安全控制系统的研究就显得非常重要。Acegi提供了对Spring应用安全的支持,然而 Acegi本身提供的实例并不能满足大规模的复杂的权限需求,本文通过扩展Acegi的数据库设计就可满足复杂的权限需求。然而,怎么将Acegi应用到非Spring的系统中,还有待进一步研究。
Java_苏先生:专注于Java开发技术的研究与知识分享!
————END————