《pro Spring》学习笔记之Spring HTTP 远程方法调用集成Tomcat实现安全验证

 

package  ch16.SecureHTTP;

import  org.apache.commons.httpclient.Credentials;
import  org.apache.commons.httpclient.HttpClient;
import  org.apache.commons.httpclient.UsernamePasswordCredentials;
import  org.springframework.beans.factory.FactoryBean;
import  org.springframework.beans.factory.InitializingBean;





public   class  HttpClientFactoryBean  implements  InitializingBean, FactoryBean  {
    
private HttpClient httpClient;
    
private String username;
    
private String password;
    
private String authenticationHost;
    
private String authenticationRealm;
    
public HttpClient getHttpClient() {
        
return httpClient;
    }


    
public void setHttpClient(HttpClient httpClient) {
        
this.httpClient = httpClient;
    }


    
public String getUsername() {
        
return username;
    }


    
public void setUsername(String username) {
        
this.username = username;
    }


    
public String getPassword() {
        
return password;
    }


    
public void setPassword(String password) {
        
this.password = password;
    }


    
public String getAuthenticationHost() {
        
return authenticationHost;
    }


    
public void setAuthenticationHost(String authenticationHost) {
        
this.authenticationHost = authenticationHost;
    }


    
public String getAuthenticationRealm() {
        
return authenticationRealm;
    }


    
public void setAuthenticationRealm(String authenticationRealm) {
        
this.authenticationRealm = authenticationRealm;
    }


    
public void afterPropertiesSet() throws Exception {
        
//构造HttpClient对象
        httpClient=new HttpClient();
        httpClient.getState().setAuthenticationPreemptive(
true);
        Credentials credentials
=new UsernamePasswordCredentials(username,password);
        httpClient.getState().setCredentials(authenticationRealm,authenticationHost,credentials);
      
    }


    
public Object getObject() throws Exception {
    
        
return httpClient;
    }


    
public Class getObjectType() {    
        
return HttpClient.class;
    }


    
public boolean isSingleton() {
        
return true;
    }


}

我们在访问Spring HTTP 远程方法的时候,没有任何的安全机制,只要知道服务接口和WSDL,都可以访问,本文讲结合Tomcat的角色机制,为HTTP远程方法调用加入安全验证机制

服务端:

服务接口:

 

package  ch16.SecureHTTP;
public   interface  HelloWorld  {
    
public String getMessage();
}

 

package  ch16.SecureHTTP;
public   class  SimpleHelloWorld  implements  HelloWorld  {
    
public String getMessage() {
        
return "hello world secure http";
    }

}

 配置文件:httpInvoker-servlet.xml(WEB-INF下)

 

<? xml version="1.0" encoding="UTF-8" ?>
< beans
    
xmlns ="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" >
< bean  id ="defaultHandlerMapping"  class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" >
</ bean >

< bean  name ="/helloWorld"  class ="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter" >
  
< property  name ="service" >
    
< bean  class ="ch16.SecureHTTP.SimpleHelloWorld" />
  
</ property >
  
< property  name ="serviceInterface" >
    
< value > ch16.SecureHTTP.HelloWorld </ value >
  
</ property >
</ bean >
</ beans >

 

web.xml

 

< context-param >
      
< param-name > contextConfigLocation </ param-name >
      
< param-value > /WEB-INF/httpInvoker-servlet.xml </ param-value >
    
</ context-param >
    
    
< servlet >
      
< servlet-name > context </ servlet-name >
      
< servlet-class > org.springframework.web.context.ContextLoaderServlet </ servlet-class >
      
< load-on-startup > 1 </ load-on-startup >
    
</ servlet >     
  
< servlet >
      
< servlet-name > httpInvoker </ servlet-name >
      
< servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >
      
< load-on-startup > 3 </ load-on-startup >
    
</ servlet >
  
   
< servlet-mapping >
    
< servlet-name > httpInvoker </ servlet-name >
    
< url-pattern > /http/* </ url-pattern >
  
</ servlet-mapping >

  
<!--  HTTP 安全性配置  -->
  
< security-constraint >
    
< web-resource-collection >
       
< web-resource-name > Secure HTTP Services </ web-resource-name >
       
< url-pattern > /http/helloWorld </ url-pattern >   <!--  spring配置文件中的bean name  -->
    
</ web-resource-collection >
    
< auth-constraint >
      
< role-name > manager </ role-name >
    
</ auth-constraint >
  
</ security-constraint >
  
  
< login-config >
    
< auth-method > BASIC </ auth-method >
    
< realm-name > ProSpringStudyWeb </ realm-name >
  
</ login-config >
  
  
< security-role >
    
< role-name > manager </ role-name >
  
</ security-role >

 

主主要是的最后一段,这里使用了tomcat-user.xml文件中定义的manager角色作为验证,至于这个角色的用户名和密码,可以在tomcat-user.xml中配置,如下:

 

<? xml version='1.0' encoding='utf-8' ?>
< tomcat-users >
  
< role  rolename ="manager" />
  
< role  rolename ="admin" />
  
< user  username ="admin"  password ="1234"  roles ="admin,manager" />
</ tomcat-users >

 

启动服务器,运行http://localhost:81/ProSpringStudyWeb/http/helloWorld (具体访问路径跟你你自己的project)
会出现一个要求输入用户名和密码的提示窗口,到此,服务端配置成功了,下面我们看客户端的实现

客户端:

部署一个安全的HTTP服务是件很容易的事情,而访问他就不那么简单了,就拿HttpInvokerProxyFactoryBean来说,这个Bean可以由内置的JDK HTTP支持,也可由commons httpClient project来支持,内置的JDK HTTP不支持HTTP基本验证,这意味着你需要使用HttpClient去访问一个安全服务,配置HttpInvokerProxyFactoryBean,我们需要使用HttpClient的CommonsHttpInvokerRequestExecutor的实例中对httpInvokerRequestExecutor的特征进行下一步设置

这将事情变得复杂了。CommonsHttpInvokerRequestExecutor不允许你将用户名和密码作为属性设置,但是他确实允许你访问HttpClient这个类所产生的实例,这是HttpClient project的核心。但是,你不可能使用Spring的依赖注入配置HttpClient的基本认证功能的凭证(因为不是setter/getter属性),所以,我们使用了Spring的FactoryBea返回一个HttpClient的恰当配置的实例,关于FactoryBean的介绍,请参考http://blog.csdn.net/daryl715/archive/2007/07/06/1681055.aspx,我们用一个HttpClientFactoryBean类来完成HttpClient实例的装配

HttpClientFactoryBean

 

package  ch16.SecureHTTP;

import  org.apache.commons.httpclient.Credentials;
import  org.apache.commons.httpclient.HttpClient;
import  org.apache.commons.httpclient.UsernamePasswordCredentials;
import  org.springframework.beans.factory.FactoryBean;
import  org.springframework.beans.factory.InitializingBean;





public   class  HttpClientFactoryBean  implements  InitializingBean, FactoryBean  {
    
private HttpClient httpClient;
    
private String username;
    
private String password;
    
private String authenticationHost;
    
private String authenticationRealm;
    
public HttpClient getHttpClient() {
        
return httpClient;
    }


    
public void setHttpClient(HttpClient httpClient) {
        
this.httpClient = httpClient;
    }


    
public String getUsername() {
        
return username;
    }


    
public void setUsername(String username) {
        
this.username = username;
    }


    
public String getPassword() {
        
return password;
    }


    
public void setPassword(String password) {
        
this.password = password;
    }


    
public String getAuthenticationHost() {
        
return authenticationHost;
    }


    
public void setAuthenticationHost(String authenticationHost) {
        
this.authenticationHost = authenticationHost;
    }


    
public String getAuthenticationRealm() {
        
return authenticationRealm;
    }


    
public void setAuthenticationRealm(String authenticationRealm) {
        
this.authenticationRealm = authenticationRealm;
    }


    
public void afterPropertiesSet() throws Exception {
        
//构造HttpClient对象
        httpClient=new HttpClient();
        httpClient.getState().setAuthenticationPreemptive(
true);
        Credentials credentials
=new UsernamePasswordCredentials(username,password);
        httpClient.getState().setCredentials(authenticationRealm,authenticationHost,credentials);
      
    }


    
public Object getObject() throws Exception {
    
        
return httpClient;
    }


    
public Class getObjectType() {    
        
return HttpClient.class;
    }


    
public boolean isSingleton() {
        
return true;
    }


}

 

配置文件:

 

<? xml version="1.0" encoding="UTF-8" ?>
< beans
    
xmlns ="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" >
 
< bean  id ="helloWorldService"  class ="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >
  
< property  name ="serviceUrl" >
    
< value > http://localhost:81/ProSpringStudyWeb/http/helloWorld </ value >
  
</ property >
  
< property  name ="serviceInterface" >
    
< value > ch16.SecureHTTP.HelloWorld </ value >
  
</ property >
  
< property  name ="httpInvokerRequestExecutor" >
    
< ref  bean ="requestExecutor" />
  
</ property >
</ bean >

< bean  id ="requestExecutor"  class ="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor" >
  
< property  name ="httpClient" >
    
<!--  使用Spring FactoryBean返回HttpClient实例,并定义好tomcat-user.xml中的正确用户名  -->
    
< bean  class ="ch16.SecureHTTP.HttpClientFactoryBean" >
      
< property  name ="username" >
        
< value > admin </ value >
      
</ property >
      
< property  name ="password" >
        
< value > 1234 </ value >
      
</ property >
    
</ bean >
  
</ property >
</ bean >
</ beans >

 

测试代码:

 

package  ch16.SecureHTTP;

import  java.io.IOException;

import  javax.servlet.ServletException;
import  javax.servlet.http.HttpServlet;
import  javax.servlet.http.HttpServletRequest;
import  javax.servlet.http.HttpServletResponse;

import  org.springframework.context.ApplicationContext;
import  org.springframework.context.support.ClassPathXmlApplicationContext;

public   class  SecureHttpClient  extends  HttpServlet  {


    
public static void main(String args[]){

        ApplicationContext context 
= new ClassPathXmlApplicationContext("ch16/SecureHTTP/applicationContext-client.xml");
        HelloWorld helloWorld
=(HelloWorld)context.getBean("helloWorldService");
        System.out.println(helloWorld.getMessage());
    }


}

 

如果配置文件中的用户名密码正确,则会打印出hello world secure http.如果用户名密码错误,则会出现以下异常

log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" org.springframework.remoting.RemoteAccessException: Cannot access HTTP invoker remote service at [http://localhost:81/ProSpringStudyWeb/http/helloWorld]; nested exception is org.apache.commons.httpclient.HttpException: Did not receive successful HTTP response: status code = 401, status message = [Unauthorized]
Caused by: org.apache.commons.httpclient.HttpException: Did not receive successful HTTP response: status code = 401, status message = [Unauthorized]
 at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.validateResponse(CommonsHttpInvokerRequestExecutor.java:183)
 at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.doExecuteRequest(CommonsHttpInvokerRequestExecutor.java:104)
 at org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor.executeRequest(AbstractHttpInvokerRequestExecutor.java:134)
 at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.java:177)
 at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.java:154)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
 at $Proxy0.getMessage(Unknown Source)
 at ch16.SecureHTTP.SecureHttpClient.main(SecureHttpClient.java:20)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值