Acegi 为 Web services 的安全护航

2023-11-20 22:58
文章标签 安全 web services 护航 acegi

本文主要是介绍Acegi 为 Web services 的安全护航,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 原文网址:http://www.oschina.net/question/12_18986

安全,可是说是个老生常谈的话题,也可以说是个永恒的话题,无论是在那个领域,那个行业,安全都是非常的重要,写本文时正好看到一些矿难和香港游客 在印尼发生灾难的新闻,可见我们周围到处都需要安全保驾护航,尽管安全是相对的,但不采取任何措施来应对安全问题带来的挑战,其后果将是惨不忍睹的,因此 我们要重视安全性问题,无论是在生活中,还是在软件领域,毕竟生活幸福,使用的软件安全,都是我们希望的。闲话少说,下面我们就针对 Web Services 的安全问题逐一分析,讲解;首先我们要介绍下 Acegi(Spring Security)。

Acegi(Spring Security) 介绍

Acegi 是一个用于 Spring Framework 的安全框架,能够和目前流行的 Web 容器无缝集成。它使用了 Spring 的方式提供了安全和认证安全服务服务,包括使用 Bean Context,拦截器和面向接口的编程方式。因此,Acegi 安全系统 能够轻松地适用于复杂的安全需求。

Acegi 的出现是令软件开发人员兴奋,激动,欢呼的,用福音来形容一点不为过呀。解决了 Java EE 安全性编程模型下的众多弊端,比如:便携性差,因 Java EE 应用必须使用容器提供的一些专有描述符 ; 开发人员要理解大量的专有描述符也不是一件容易的事情,毕竟不同的容器的描述符存在一定的差别的,有时候就是写错了一点,都需要好长时间的调试才能得以解 决 ; 还有就是使用 Java EE 安全性编程模型的应用测试工作很难进行,尤其是在 TDD 流行的当下,不能方便,顺利的进行测试的开发可谓是一大弊端呀。Acegi 就是一名神医,将这些弊病统统解决,尤其是 Spring Security 的出现使应用 Acegi 更加方便,快捷,下面我们就进入 Spring Security 的旅程。

第一眼 Spring Security

准备环境

  1. 下载 spring-security-3.0.3.RELEASE.zip 包从 http://www.springsource.com/download/community 这个链接 ;
  2. 将 spring-security-samples-contacts-3.0.3.RELEASE.war 和 spring-security-samples-tutorial-3.0.3.RELEASE.war 复制到 apache-tomcat-6.0.18 的 webapps 下;

步骤 2 中的两个 war 包是 spring-security-3.0.3.RELEASE.zip 解压后包含的两个 Demo,下面我们就是通过这两个 Demo 来看看 Spring Security 给我们带来的快感,每个的 Demo 我们都会做详细的解释,以使读者能很清楚的了解 Spring Security 的工作过程。

用户场景

下面我们模拟下经常应用的场景,比如用户登录后可以操作业务方法,我们知道业务方法不是随意让用户可以调用的,有些业务方法很敏感,比如电信的计费方法, 涉及分成,结算等关键业务,所以需要有足够权限的用户才可以调用,因此我们通常在业务方法前加入一层来拦截用户请求,根据用户权限来判断是否可以访问。


图 1. 用户场景实例图

下面我们主要来研究下在 security 层是怎样实现业务方法保护的。

初识 Acegi(contacts Demo)

找到 TOMCAT_HOME 下的 bin 目录然后点击 startup.bat 来完成启动 tomcat 的操作,然后我们在浏览器中输入 http://localhost:8080/spring-security-samples-contacts-3.0.3.RELEASE URL, 我们就可以看到应用的主页了,从主页内容中我们能够知道这个 Demo 所应用的 Spring Security 的功能,比如:Remember-me 认证服务,form-based 认证,BASIC 认证和 Database-sourced security data 等。然后点击 Manage 超链接将会转到登录界面,在登录界面中列出了数据库中的所有用户信息,包括用户名,密码和是否可用字段。我们可以清楚的看到 Contacts Demo 使用的是 HTTP 表单认证,使用自定义 Web 表单页面来收集用户凭证信息的这一认证机制由于用户交互性友好等方面受到广大用户的青睐。大家应该很熟悉 HTTP BASIC 认证吧,下面我们就通过修改 applicationContext-security.xml 文件来体验一下这种认证方式,将 applicationContext-security.xml 文件中清单 3 列出的内容注释掉。


清单 1. 注释掉的内容

				  
<form-login login-page="/login.jsp" 
authentication-failure-url="/login.jsp?login_error=1"/> 

 

注:上面的内容是指定了登录的页面,用户登录时将显示这个指定的页面的。

然后我们重新启动 tomcat 容器,输入 http://localhost:8080/spring-security-samples-contacts-3.0.3.RELEASE/hello.htm URL. 然后点击 Manage 超链接,显示的这个界面是由浏览器生成的,和 XP 系统登录界面很像吧。

另外一个 Demo spring-security-samples-tutorial-3.0.3.RELEASE.war 我们不做过多的解释了,有兴趣的读者可以自行研究下,如有疑问可以和我联系的。我们知道 Acegi 即可以保护 Web 资源,又可以保护服务层的业务方法,还可以保护领域对象。保护服务层的业务方法的这个功能和本文要讲解的 Web Service 密切相关,所以下面我们将通过一个例子来详细讲解下 Acegi 是怎样来保护服务层的业务方法的,以使大家有一个全面的理解。

Spring security(Acegi) 保护服务层的业务方法

首先新建一个 java project 命名为 acegi-method-project,然后新建一个接口命名为 EmployeeManager,接口内容如清单 2 所示:


清单 2. EmployeeManager.java 类代码

				  
package org.ibm.acegi.beans; 
import java.util.List; 
public interface EmployeeManager { 
/** 
* Delete employee by employee Id 
* @param id 
*/ 
public void deleteEmployeeById(int id);  
/** 
* get all employees     
* @param id 
* @return List<Employee> 
*/ 
public List findAllEmployees(); 
}

 

可以看出我们需要两个方法 deleteEmployeeById 和 findAllEmployees, 然后新建一个实现类 implement 接口 EmployeeManager,命名为 EmployeeManagerImpl,代码内容如清单 4 所示:


清单 3. EmployeeManagerImpl.java 类代码

				  
package org.ibm.acegi.beans; 
import java.util.ArrayList;import java.util.List;import org.apache.log4j.Logger; 
public class EmployeeManagerImpl implements EmployeeManager {
private static Logger logger = Logger.getLogger(EmployeeManagerImpl.class);  
@Override 
public void deleteEmployeeById(int id) {
System.out.println("deleteEmployeeById()");  } 
@Override 
public List findAllEmployees() {
List list = new ArrayList();
list.add("findEmployeeById");
System.out.println("findEmployeeById()");  r
eturn list; }} 

 

方法 deleteEmployeeById 通过员工 Id 来做删除操作,这里我们只是打印一条信息而已,没有实现具体过程 ; 同样 findAllEmployees 方法也是打印一条信息。上面我们说过了,我们要做的是服务层的业务方法的保护,所以要添加清单 5 所示的内容到 applicationContext.xml,applicationContext.xml 中,大家都很熟悉吧? spring 的配置文件,这里不详细介绍了。


清单 4. MethodSecurityInterceptor 业务方法保护

				  
<bean id="employeeManagerSecurity" 
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">  
<property name="validateConfigAttributes">  
<value>true</value>  </property>  
<property name="authenticationManager">  
<ref bean="authenticationManager"/> 
</property>  
<property name="accessDecisionManager">  
<ref bean="accessDecisionManager"/>  
</property>  <property name="runAsManager"> 
<ref bean="runAsManager"/>  
</property>  <property name="objectDefinitionSource"> 
<value>org.ibm.acegi.beans.EmployeeManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
org.ibm.acegi.beans.EmployeeManager.findAllEmployees = 
ROLE_TELLER,ROLE_SUPERVISOR,RUN_AS_SERVER</value> 
</property> 
</bean>  

 

从上面我们可以看到 MethodSecurityInterceptor 拦截器暴露的 objectDefinitionSource 属性类似与 FilterSecurityInterceptor 过滤器暴露的 objectDefinitionSource 属性,不过前者是针对服务层的业务方法的,而后者针对的是 Web 资源,HTTP URL。我们来简单介绍下 objectDefinitionSource 属性的定义形式,“=”左边的以全包路径列出的为方法名,而“=”右边的内容代表了此方法需要的角色集合,我们需要用逗号来间隔多个角色。

我们再来看下上面需要的 authenticationManager 属性,内容见清单 6 所示:


清单 5. authenticationManager 内容

				  
<bean id="authenticationManager" 
class="org.acegisecurity.providers.ProviderManager">  
<property name="providers">  
<list>  
<ref local="daoAuthenticationProvider"/>  
<bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"> 
<property name="key" value="changeThis"/> 
</bean><beanclass
="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>  </list>  
</property> 
</bean> 

 

清单 6 的内容很关键,我们看到 ProviderManager 这个类,他是认证管理器的实现,可以配置多种认证管理源来认证用户的,通过 list 属性我们可以很容易的明白这一点。我们再来看一下这里面提供的一种认证源 daoAuthenticationProvider,内容见清单 7 所示:


清单 6. daoAuthenticationProvider 内容

				  
<bean id="daoAuthenticationProvider"
class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> 
<property name="userDetailsService" 
ref="userDetailsService"/> 
<property name="userCache">  
<bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache"> 
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">  
<property name="cacheManager">  
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/> 
</property>  
<property name="cacheName" 
value="userCache"/> 
</bean> 
</property> 
</bean> 
</property>  
</bean> 

 

userDetailsService 属性也是一个很关键的,详细配置见清单 8 所示:


清单 7. userDetailsService 内容

				  
<bean id="userDetailsService"
class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userProperties">  
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location"value="users.properties"/>  
</bean></property> 
</bean>  

 

它提供用户的核心信息,包括用户名,用户密码,账户状态等信息,这是用户信息的入口。

单元测试 - 保护业务方法

对于一个开发者来说,单元测试永远是必不可少的,尤其是在 TDD 流行的今天来说,下面我们新建一个测试类命名为 EmployeeManagerImplTest 继承自 TestCase, 然后加入一个方法用来设置认证源命名为 createSecureContext,源码内容见清单 10 所示:


清单 8. createSecureContext 内容

				  
private static void createSecureContext(final BeanFactory bf, 
final String username, final String password) {  
AuthenticationProvider provider 
= (AuthenticationProvider) bf.getBean("daoAuthenticationProvider");  
Authentication auth
= provider.authenticate(
new UsernamePasswordAuthenticationToken(username, password));  
SecurityContextHolder.getContext().setAuthentication(auth);  
} 

 

这个方法提供了需要验证的基础信息,包括用户名,密码。

单元测试类的 teardown 方法内容如清单 11 所示:


清单 9. teardown 内容

				  
public void teardown() {  
SecurityContextHolder.setContext(new SecurityContextImpl());  
} 

 

加入我们需要测试类 EmployeeManagerImpl 的本次需要测试的方法,代码内容见清单 12 所示:


清单 10. EmployeeManagerImpl 的测试方法

				  
/** 
* test deleteEmployeeById method. 
*/ 
public void testDeleteEmployeeById() {  
EmployeeManager employeeManager = 
(EmployeeManager) factory.getBean("employeeManager");  
createSecureContext(factory, "administrator", "administrator");  
employeeManager.deleteEmployeeById(1011);  
}     
/** 
* test findAllEmployees method. 
*/ 
public void testFindAllEmployees() {  
EmployeeManager employeeManager = 
(EmployeeManager) factory.getBean("employeeManager");  
createSecureContext(factory, "sale_user", "sale_user");  
employeeManager.findAllEmployees();  
}  

 

测试类 EmployeeManagerImplTest 依赖的泪如清单 13 所示:


清单 11. 测试类 EmployeeManagerImplTest 需要导入的依赖类

				  
import junit.framework.TestCase; 
import org.acegisecurity.Authentication; 
import org.acegisecurity.context.SecurityContextHolder; 
import org.acegisecurity.context.SecurityContextImpl; 
import org.acegisecurity.providers.AuthenticationProvider; 
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; 
import org.ibm.acegi.beans.EmployeeManager; 
import org.springframework.beans.factory.BeanFactory; 
import org.springframework.beans.factory.xml.XmlBeanFactory; 
import org.springframework.core.io.ClassPathResource; 
import org.springframework.core.io.Resource; 

 

至此我们的测试类全部完成了,我们可以运行该类,看一下效果,右键然后选择 Run as 然后选择 Junit test,result 见清单 14 所示:


清单 12. 测试结果

				  
Test-begin 
test deleteEmployeeById() method! 
test findEmployeeById() method! 
---sucess---- 
Test-end 

 

重写部分方法 - 了解整个工作过程

为了使大家更清楚的了解 Acegi 的工作过程,我们重写了 AfterInvocationProvider 和 ApplicationEventPublisher 这两个接口的方法,新建两个类,AfterInvocationProviderImpl 实现了 AfterInvocationProvider 接口,ApplicationEventPublisherImpl 实现了 ApplicationEventPublisher 接口,代码内容分别见清单 15 和清单 16 所示:


清单 13. AfterInvocationProviderImpl 类代码

				  
public class AfterInvocationProviderImpl implements AfterInvocationProvider { 
private static Logger logger = Logger 
.getLogger(AfterInvocationProviderImpl.class); 
@Override 
public boolean supports(ConfigAttribute attribute) { 
System.out.println("ConfigAttribute value is: " 
+ attribute);
if (attribute.getAttribute().equals("EMPLOYEESECURITY_CUSTOMER")) 
{return true;}return false;} 
@Override 
public boolean supports(Class clazz) { 
System.out.println("Security Type: " + clazz); 
if (clazz == MethodInvocation.class) {return true;} 
return false;} 

 

可以看出我们重写了 supports 方法,如果属性值存在的话返回真,否则返回假。并打印一些信息。


清单 14. ApplicationEventPublisherImpl 类代码

				  
public class ApplicationEventPublisherImpl implements ApplicationEventPublisher { 
private static Logger logger = Logger.getLogger(ApplicationEventPublisherImpl.class);  
@Override 
public void publishEvent(ApplicationEvent event) { 
System.out.println("Security method: " + event);  
} 
} 

 

publishEvent 方法我们加入了一些输出信息,这样有助于我们更好的了解 Spring Security 的工作过程,以使我们能更好的控制它。

然后我们修改下 applicationContext.xml 文件,在 bean employeeManagerSecurity 中添加属性内容见清单 17 所示:


清单 15. applicationContext 文件修改的内容

				  
<property name="applicationEventPublisher">  
<bean class="org.ibm.acegi.beans.ApplicationEventPublisherImpl"/>  
</property>  
<property name="afterInvocationManager">  
<ref bean="afterInvocationManager"/>  
</property> 

 

然后再添加一个 bean 名称为 afterInvocationManager,内容见清单 18 所示:


清单 16. afterInvocationManager bean 内容

				  
<bean id="afterInvocationManager" 
class="org.acegisecurity.afterinvocation.AfterInvocationProviderManager">  
<property name="providers">  
<list>  
<bean class="org.ibm.acegi.beans.AfterInvocationProviderImpl"/>  
</list>  
</property>  
</bean> 

 

接下来我们在运行下单元测试文件 EmployeeManagerImplTest,运行结果如清单 19 所示:


清单 17. 重构后的单元测试运行结果

				  
Test-begin 
Security Type: interface org.aopalliance.intercept.MethodInvocation 
ConfigAttribute value is: EMPLOYEESECURITY_CUSTOMER 
Security method: org.acegisecurity.event.authorization 
.AuthorizedEvent[source=ReflectiveMethodInvocation: 
public abstract void org.ibm.acegi.beans.EmployeeManager.deleteEmployeeById(int); 
target is of class [org.ibm.acegi.beans.EmployeeManagerImpl]] 
test deleteEmployeeById() method! 
Security method: org.acegisecurity.event.authorization 
.AuthorizedEvent[source=ReflectiveMethodInvocation: 
public abstract java.util.List org.ibm.acegi.beans.EmployeeManager.findAllEmployees(); 
target is of class [org.ibm.acegi.beans.EmployeeManagerImpl]] 
test findEmployeeById() method! 
---sucess---- 
Test-end 

 

从结果中我们能很清晰的知道 Acegi 的加载过程,有助于我们更好的理解,使用好 Acegi。通过上面的学习我们对 Spring security(Acegi) 有了一个初步的了解,并对其是怎样来对服务层的业务方法进行保护有了更清晰的认识,为我们接下来的知识讲解铺平了道路,下面我们就介绍下 Acegi 是怎样为 Web Service 提供保护的,首先我们新建一个 Web Service,我们知道开发 Web Service 的方法有很多种,我还是比较喜欢用 CXF 的。

开发 Web Services

新建一个 Java project 工程,命名为 ws _example, 创建 service 类,CXFService.java 和 CXFServiceImpl.java, 代码分别见清单 7 和清单 8 所示:


清单 18. CXFService.java

				  
package org.ibm.cxf.service; 
public interface CXFService { 
public String sayHello(String name); 
} 



清单 19. CXFServiceImpl.java

				  
package org.ibm.cxf.service.impl; 
import org.ibm.cxf.service.CXFService; 
public class CXFServiceImpl implements CXFService{ 
public String sayHello(String name) {return "Hello "+name;}} 

 

接下来,我们要新建一个 cxf-servlet.xml 和 web.xml 文件,文件内容分别如清单 9 和清单 10 所示:


清单 20. cxf-servlet.xml

				  
<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:simple="http://cxf.apache.org/simple"
xmlns:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://cxf.apache.org/bindings/soap 
http://cxf.apache.org/schemas/configuration/soap.xsd 
http://cxf.apache.org/simple 
http://cxf.apache.org/schemas/simple.xsd"> 
<simple:server id="CXFservice" serviceClass="org.ibm.cxf.service.CXFService"
address="/CXFService"><simple:serviceBean><bean 
class="org.ibm.cxf.service.impl.CXFServiceImpl" /> 
</simple:serviceBean></simple:server></beans> 

 

注意一下,simple:server 后的 serviceClass 指定的是接口的名称而 simple:serviceBean 后指定的是实现类的名称,这个地方费了我好多时间呀,郁闷。


清单 21. web.xml

				  
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd"><web-app> 
<display-name>cxf</display-name> 
<description>cxf</description><servlet> 
<servlet-name>cxf</servlet-name> 
<display-name>cxf</display-name> 
<description>Apache CXF Endpoint</description><servlet-class> 
org.apache.cxf.transport.servlet.CXFServlet</servlet-class> 
<load-on-startup>1</load-on-startup></servlet> 
<servlet-mapping><servlet-name>cxf</servlet-name> 
<url-pattern>/services/*</url-pattern></servlet-mapping><session-config> 
<session-timeout>30</session-timeout></session-config> 
</web-app> 

 

上面代码配置了一个 servlet,名称为 cxf。

最后我们还是需要新建一个 ant 脚本来打包,build.xml,其脚本如清单 11 所示:


清单 22. build.xml for CXFService

				  
<project name="service" basedir="." default="war"> 
<property name="dist.dir" value="${basedir}/WEB-INF" /> 
<property name="dist.dir.classes" 
value="${dist.dir}/classes" /> 
<path id="build.class.path"> 
<fileset dir="${basedir}/lib"> 
<include name="*.jar" /></fileset> 
</path><target name="war" depends=""> 
<javac srcdir="src" 
destdir="${dist.dir.classes}"
includes="org/ibm/cxf/service/*/*"> 
<classpath refid="build.class.path" /> 
</javac><war destfile="${dist.dir}/cxf.war" 
webxml="${dist.dir}/web.xml"> 
<classes dir="${dist.dir.classes}" /> 
<lib dir="${basedir}/lib" /> 
<webinf dir="${dist.dir}"><include name="cxf-servlet.xml" /> 
</webinf></war></target></project> 

 

运行 ant 脚本,将生成的 cxf.war 包放到 tomcat 的部署目录下,启动 tomcat,待启动完成后,我们在浏览器中输入 http://localhost:8080/cxf/services/CXFService?wsdl 将显示如下信息:

  <?xml version="1.0" encoding="UTF-8" ?>  -
<wsdl:definitions name="CXFService" 
targetNamespace="http://service.cxf.ibm.org/"
xmlns:ns1="http://schemas.xmlsoap.org/wsdl/soap/http" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://service.cxf.ibm.org/" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
-<wsdl:types>
-<xsd:schema attributeFormDefault="unqualified" 
elementFormDefault="qualified" 
targetNamespace="http://service.cxf.ibm.org/" 
xmlns:tns="http://service.cxf.ibm.org/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
<xsd:element name="sayHello" type="tns:sayHello" /> 
……
</wsdl:definitions>

 

出现如上信息表示 service 发布成功了,关于 service 的详细信息在这个 WSDL 文件中都有定义,如出现问题请仔细检查以上步骤。

下面我们测试下 service 是否可用。

单元测试

新建一个 JUnit 测试类 CXFServiceTest,代码如清单 12 所示:


清单 23. CXFServiceTest.java

				  
package org.ibm.axis.service.client; 
import junit.framework.Assert; 
import org.apache.cxf.frontend.ClientProxyFactoryBean; 
import org.ibm.cxf.service.CXFService; 
import org.junit.Test; 
public class CXFServiceTest { 
@Test 
public void testSayHello(){ 
ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); 
factory.setServiceClass(CXFService.class); 
factory.setAddress("http://localhost:8080/cxf/services/CXFService"); 
CXFService client = (CXFService) factory.create(); 
String response = client.sayHello("jack"); 
Assert.assertEquals("Hello jack", response); 
} 
} 

 

其中 Address 可以从上面的 WSDL 文件中得到。

运行 JUnit test, 结果如图 6 所示:


图 2. Junit service 测试结果

可见这个 Web Service 方法是可用的,对于这个 Web Service 的保护我们将采取拦截器的方式。

对于 Interceptor 更多知识请大家自行查看相关资料,下面我们新建一个拦截器 SecurityInInterceptor 继承自 AbstractPhaseInterceptor<Message> 类,代码见清单 26 所示:


清单 24. SecurityInInterceptor 拦截器代码

				  
public class SecurityInInterceptor extends AbstractPhaseInterceptor<Message> { 
private static Log logger = LogFactory.getLog(SecurityInInterceptor.class); 
private AuthenticationManager authenticationManager; 
public void setAuthenticationManager( 
AuthenticationManager authenticationManager) { 
this.authenticationManager = authenticationManager; 
} 
public SecurityInInterceptor() { 
super(Phase.INVOKE);} 
public void handleMessage(Message message) throws Fault { 
String baseAuth = null; 
Map<String, List<String>> reqHeaders = CastUtils 
.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS)); 
if (reqHeaders != null) { 
for (Map.Entry<String, List<String>> e : reqHeaders.entrySet()) { 
if ("Authorization".equalsIgnoreCase(e.getKey())) 
baseAuth = e.getValue().get(0);} 
} 
if ((baseAuth != null) && baseAuth.startsWith("Basic ")) { 
byte[] base64Token;String username = "";String password = ""; 
try { 
base64Token = baseAuth.substring(6).getBytes("UTF-8");
String token=new String(Base64.decodeBase64(base64Token),"UTF-8"); 
int delim = token.indexOf(":");
if (delim != -1) 
{username = token.substring(0, delim);
password = token.substring(delim + 1);} 
Authentication authResult = 
authenticationManager.authenticate
(new UsernamePasswordAuthenticationToken(username, password)); 
if(logger.isDebugEnabled()){logger.
debug("Authentication success:"+ 
authResult.toString());}SecurityContextHolder.getContext()
.setAuthentication(authResult);} 
catch (AuthenticationException failed) 
{if (logger.isDebugEnabled()) 
{logger.debug("Authentication request for user '"
+ username+ "' failed: " + failed.toString());}
SecurityContextHolder.clearContext();throw new Fault(failed); 
} catch (Exception e){SecurityContextHolder.getContext().setAuthentication(null); 
throw new Fault(e);}}}} 

 

再建一个 SecurityOutInterceptor 拦截器,代码见清单 26 所示:


清单 25. SecurityOutInterceptor 拦截器内容

				  
public class SecurityOutInterceptor extends AbstractPhaseInterceptor<Message> { 
public SecurityOutInterceptor() { 
super(Phase.SEND);} 
public void handleMessage(Message message) throws Fault { 
SecurityContextHolder.clearContext();}} 

 

然后我们修改 cxf-servlet.xml 文件,修改内容如清单 27 所示:


清单 26. 修改 cxf-servlet.xml 的内容

				  
<jaxws:endpoint id="CXFservice"
implementor="org.ibm.cxf.service.impl.CXFServiceImpl" address="/CXFService"> 
<jaxws:features> 
<bean class="org.apache.cxf.feature.LoggingFeature" /> 
</jaxws:features> 
<jaxws:inInterceptors> 
<bean class="org.ibm.acegi.beans.security.SecurityInInterceptor"> 
<property name="authenticationManager" ref="authenticationManager" /> 
</bean> 
<bean class="org.ibm.acegi.beans.security.SecurityOutInterceptor" /> 
</jaxws:inInterceptors> 
</jaxws:endpoint> 

 

这样当我们访问 Web Service 时候将会被这个拦截器拦截,我们看下 authenticationManager 这个属性很熟悉吧?对,我们上面讲解服务层的业务方法保护那部分提到了,最后根据 applicationContext.xml 文件做相应的修改后,我们就可以使用 spring security(Acegi) 为我们开发的 Web Service 方法提供保护了,以上对业务方法保护的过程我们可以用图 7 来简单概括下。


图 3. 业务保护方法时序图 mywang2011-03-22T11:17:00 图片顺序不对

总结

本文首先通过 Spring Security(Acegi) 自带的两个例子带领大家认识一下 Spring Security(Acegi) 的面貌,然后通过一个具体实例来讲解 Spring Security(Acegi) 是怎样来保护服务层的业务方法的,然后用 CXF 开发了一个 Web Service 并实现了 Spring Security(Acegi) 对它的保护。每一个实例都是通过从新建工程开始一步一步的带领大家来继续的,我们知道仅仅通过一片文章来很详细的将 Spring Security(Acegi) 保护 Web Services 的方方面面都阐述的很清楚,那是不可能的。

本文提供了最基本,最基础的开发过程,任何复杂的事务归根结底还是源于基础,有句话是这样说的,“授之以鱼,不如授之以渔”,我想只要方向对了,知道如何下手了,就不会有大的失误,

 

这篇关于Acegi 为 Web services 的安全护航的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/398039

相关文章

Java Web指的是什么

Java Web指的是使用Java技术进行Web开发的一种方式。Java在Web开发领域有着广泛的应用,主要通过Java EE(Enterprise Edition)平台来实现。  主要特点和技术包括: 1. Servlets和JSP:     Servlets 是Java编写的服务器端程序,用于处理客户端请求和生成动态网页内容。     JSP(JavaServer Pages)

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

2024网安周今日开幕,亚信安全亮相30城

2024年国家网络安全宣传周今天在广州拉开帷幕。今年网安周继续以“网络安全为人民,网络安全靠人民”为主题。2024年国家网络安全宣传周涵盖了1场开幕式、1场高峰论坛、5个重要活动、15场分论坛/座谈会/闭门会、6个主题日活动和网络安全“六进”活动。亚信安全出席2024年国家网络安全宣传周开幕式和主论坛,并将通过线下宣讲、创意科普、成果展示等多种形式,让广大民众看得懂、记得住安全知识,同时还

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

9.8javaweb项目总结

1.主界面用户信息显示 登录成功后,将用户信息存储在记录在 localStorage中,然后进入界面之前通过js来渲染主界面 存储用户信息 将用户信息渲染在主界面上,并且头像设置跳转,到个人资料界面 这里数据库中还没有设置相关信息 2.模糊查找 检测输入框是否有变更,有的话调用方法,进行查找 发送检测请求,然后接收的时候设置最多显示四个类似的搜索结果

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证:Authentication1.2 鉴权:Authorization1.3 准入控制:Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes 作为一个分布式的虚拟

JavaWeb【day09】--(Mybatis)

1. Mybatis基础操作 学习完mybatis入门后,我们继续学习mybatis基础操作。 1.1 需求 需求说明: 根据资料中提供的《tlias智能学习辅助系统》页面原型及需求,完成员工管理的需求开发。 通过分析以上的页面原型和需求,我们确定了功能列表: 查询 根据主键ID查询 条件查询 新增 更新 删除 根据主键ID删除 根据主键ID批量删除

利用Django框架快速构建Web应用:从零到上线

随着互联网的发展,Web应用的需求日益增长,而Django作为一个高级的Python Web框架,以其强大的功能和灵活的架构,成为了众多开发者的选择。本文将指导你如何从零开始使用Django框架构建一个简单的Web应用,并将其部署到线上,让世界看到你的作品。 Django简介 Django是由Adrian Holovaty和Simon Willison于2005年开发的一个开源框架,旨在简