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

原创 2007年09月23日 15:08:00

 

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)

Spring 实现远程访问详解——httpinvoker

上文我们利用Spring rmi实现了Spring的远程访问《Spring 实现远程访问详解——rmi》,本文主要讲解利用HttpInvoke实现远程访问。 Spring httpInvoker使用标...
  • a123demi
  • a123demi
  • 2016年04月19日 15:01
  • 1940

Spring学习笔记之使用远程服务

远程调用是客户端应用和服务端应用之间的会话。在客户端,它所需要的一些功能并不在该应用的实现范围之内,所以应用要想能提供这些功能的·其他系统寻求帮助。而远程应用通过远程服务暴露这些功能。 RPC(re...
  • CSDN_XueXiaoQiang
  • CSDN_XueXiaoQiang
  • 2017年06月04日 16:05
  • 448

spring mvc 实现远程服务调用的几种方式

org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 实现远程服务调用 服务端 必须要实现 bean实体类  se...
  • u013378306
  • u013378306
  • 2016年02月27日 16:10
  • 8292

Spring中HttpInvoker远程方法调用总结

Spring为各种远程访问技术的集成提供了工具类。Spring远程支持是由普通(Spring)POJO实现的,这使得开发具有远程访问功能的服务变得相当容易。目前,Spring支持四种远程技术: ...
  • zebing007
  • zebing007
  • 2016年06月08日 19:18
  • 1025

Spring RMI实现远程调用及源码

1.RMI简单介绍 Spring除了使用基于HTTP协议的远程调用方案,还为开发者提供了基于RMI机制的远程调用方法,RMI远程调用网络通信实现是基于TCP/IP协议完成的,而不是通过HTTP协议。...
  • clypm
  • clypm
  • 2015年03月10日 10:16
  • 627

Spring 集成 MyBatis 笔记(Mybatis-Spring 的用法)-理论部分

我们这里以 dbcp 数据源为例。1、引入相关的 jar 包坐标依赖 org.springframework spri...
  • lw_power
  • lw_power
  • 2015年07月25日 22:50
  • 1977

spring在于tomcat的整合原理

这篇文章主要是源码的一个整理:将来要是忘了可以看看:
  • hao707822882
  • hao707822882
  • 2014年09月26日 20:19
  • 1633

使用Spring Cloud Feign远程调用

Spring Cloud Feign简介参考:http://blog.csdn.net/neosmith/article/details/52449921 根据专家学者提供的账号密码,要在用户表...
  • pomay
  • pomay
  • 2017年06月27日 11:51
  • 587

不错的Spring学习笔记(转)

Spring学习笔记(1)----简单的实例 ---------------------------------   首先需要准备Spring包,可从官方网站上下载。   下载解压后,必须的两个包是s...
  • chenqiushi205
  • chenqiushi205
  • 2016年02月17日 16:09
  • 467

Spring4实战学习笔记

《Spring4实战 第4版》2016年4月新出版的,之前的第三版看起来还是不错的,所以看到新版就直接买下来。 1.装配Bean 参考【2.2】 1.1接口只有一个现实类可以自动装配 publ...
  • unix21
  • unix21
  • 2016年05月04日 19:14
  • 4468
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:《pro Spring》学习笔记之Spring HTTP 远程方法调用集成Tomcat实现安全验证
举报原因:
原因补充:

(最多只允许输入30个字)