cxf + spring 的WS Security示例

标签: webservice | 发表时间:2015-09-14 08:00 | 作者:
出处:http://itbokeyun.com/

WSPasswordCallbackpasswordType属性和 password属性都为null,你只能获得用户名(identifier),一般这里的逻辑是使用这个用户名到数据库中查询其密码,然后再设置到 password属性,WSS4J会自动比较客户端传来的值和你设置的这个值。你可能会问为什么这里CXF不把客户端提交的密码传入让我们在 ServerPasswordCallbackHandler中比较呢?这是因为客户端提交过来的密码在SOAP消息中已经被加密为MD5的字符串,如果我们要在回调方法中作比较,那么第一步要做的就是把服务端准备好的密码加密为MD5字符串,由于MD5算法参数不同结果也会有差别,另外,这样的工作CXF 替我们完成不是更简单吗?
根据上面说的,我获取的 passwordnull,所以这里就不用自己判断密码了,只要验证用户名后,在设置密码就可以自动验证了,代码如下:

  public class ServerPasswordCallback implements CallbackHandler {    
     
     public void handle(Callback[] callbacks) throws IOException,    
	      UnsupportedCallbackException {    
	  WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];    
	  String pw = pc.getPassword();    
	  String idf = pc.getIdentifier();    
	  System.out.println("password:"+pw);    
	  System.out.println("identifier:"+idf);  
	  if(idf.endsWith("admin")){
	   pc.setPassword("admin");
	  }
      }    
     
 }

以下是源代码:

HelloWorld.java

  package com.mms.webservice;
import javax.jws.WebService;
@WebService
public interface HelloWorld { 
    String sayHi(String text); 
}

HelloWorldImpl.java

  package com.mms.webservice;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
 
@WebService
public class HelloWorldImpl implements HelloWorld { 
    public String sayHi(String text) {
	return "Hello " + text;
    }
}

ServerPasswordCallback.java

  package com.mms.webservice.test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityException;
 
public class ServerPasswordCallback implements CallbackHandler {
 
    private Map<String, String> passwords = new HashMap<String, String>();
 
    public ServerPasswordCallback() {
	passwords.put("admin", "admin");
	passwords.put("test", "test");
    }
 
    public void handle(Callback[] callbacks) throws IOException,
	    UnsupportedCallbackException {
	System.out.println("server:callbacks.length-"+callbacks.length);
	for (int i = 0; i < callbacks.length; i++) {
	    WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
	    if (!passwords.containsKey(pc.getIdentifier()))
		try {
		    throw new WSSecurityException("user not match");
		} catch (WSSecurityException e) {
		    e.printStackTrace();
		}
	    String pass = passwords.get(pc.getIdentifier());
	    pc.setPassword(pass);
	}
    }
 
}

ClientPasswordCallback.java

  package com.mms.client;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityException;
 
public class ClientPasswordCallback implements CallbackHandler {
 
    private Map<String, String> passwords = new HashMap<String, String>();
 
    public ClientPasswordCallback() {
	passwords.put("admin", "admin");
	passwords.put("test", "test");
    }
 
    public void handle(Callback[] callbacks) throws IOException,
	    UnsupportedCallbackException {
	System.out.println("client:callbacks.length-"+callbacks.length);
	for (int i = 0; i < callbacks.length; i++) {
	    WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
	    int usage = pc.getUsage();
	    if (!passwords.containsKey(pc.getIdentifier()))
		try {
		    throw new WSSecurityException("user not exists ");
		} catch (WSSecurityException e) {
		    e.printStackTrace();
		}
	    String pass = passwords.get(pc.getIdentifier());
	    if (usage == WSPasswordCallback.USERNAME_TOKEN && pass != null) {
		System.out.println("client:pass"+pass);
		pc.setPassword(pass);
		return;
	    }
	}
    }
 
}

web.xml

  <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
	    classpath:server.xml classpath:client.xml
	</param-value>
    </context-param>
 
    <listener>
	<listener-class>
	    org.springframework.web.context.ContextLoaderListener
	</listener-class>
    </listener>
 
    <servlet>
	<servlet-name>CXFServlet</servlet-name>
	<servlet-class>
	    org.apache.cxf.transport.servlet.CXFServlet
	</servlet-class>
    </servlet>
 
    <servlet-mapping>
	<servlet-name>CXFServlet</servlet-name>
	<url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

客户端spring配置文件:client.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:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="
		       http://www.springframework.org/schema/beans
		       http://www.springframework.org/schema/beans/spring-beans.xsd
		       http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
 
    <!-- 定义客户端的拦截器对象  -->
    <bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
    <bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
    <bean id="saajOut" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
    <!-- <bean id="soapheaderOut" class="com.mms.client.writeSOAPHeaderInterceptor" /> -->
    <bean id="wss4jOut" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
	<constructor-arg>
	    <map>
		<entry key="action" value="UsernameToken" />
		<entry key="passwordType" value="PasswordText" />
		<entry key="user" value="admin" />
		<entry key="passwordCallbackClass" value="com.mms.client.ClientPasswordCallback" />
	    </map>
	</constructor-arg>
    </bean>
    <!-- 客户端的配置 -->
    <jaxws:client id="client" serviceClass="com.mms.webservice.HelloWorld" address="http://127.0.0.1:8080/CXFSecurity/HelloWorld">
	<jaxws:inInterceptors>
	    <ref bean="logIn" />
	</jaxws:inInterceptors>
	<jaxws:outInterceptors>
	    <ref bean="logOut" />
	    <ref bean="saajOut" />
	    <!--<ref bean="soapheaderOut" /> -->
	    <ref bean="wss4jOut" />
	</jaxws:outInterceptors>
    </jaxws:client>
</beans>

服务器spring配置文件:server.xml

  <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation=" 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <!-- jar包中自带的cxf文件夹下的*.xml文件 -->
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    <!-- 定义服务端的拦截器对象 -->
    <bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
    <bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
    <bean id="saajIn" class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
    <!-- <bean id="soapheaderIn" class="com.mms.webservice.test.readSOAPHeaderInterceptor" /> -->
    <bean id="wss4jIn" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
	<constructor-arg>
	    <map>
		<entry key="action" value="UsernameToken" />
		<entry key="passwordType" value="PasswordText" />
		<entry key="passwordCallbackClass" value="com.mms.webservice.test.ServerPasswordCallback" />
	    </map>
	</constructor-arg>
    </bean>
    <jaxws:endpoint id="helloWorld" implementor="com.mms.webservice.HelloWorldImpl"
	address="/HelloWorld">
	<jaxws:inInterceptors>
	    <ref bean="logIn" />
	    <ref bean="saajIn" />
	    <!--<ref bean="soapheaderIn" /> -->
	    <ref bean="wss4jIn" />
	</jaxws:inInterceptors>
	<jaxws:outInterceptors>
	    <ref bean="logOut" />
	</jaxws:outInterceptors>
    </jaxws:endpoint>
 
</beans>

测试Client.java

  package com.mms.client;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mms.webservice.HelloWorld;
 
public final class Client {
 
    private Client() {
    }
 
    public static void main(String args[]) throws Exception {
		ApplicationContext  context = new ClassPathXmlApplicationContext(
		new String[] { "client.xml" });
	HelloWorld client = (HelloWorld) context.getBean("client");
	String response = client.sayHi("hello test!");
	System.out.println("Response: " + response);
    }
}

相关 [cxf spring ws] 推荐:

cxf + spring 的WS Security示例

- - RSS - IT博客云
WSPasswordCallback的 passwordType属性和 password属性都为null,你只能获得用户名(identifier),一般这里的逻辑是使用这个用户名到数据库中查询其密码,然后再设置到 password属性,WSS4J会自动比较客户端传来的值和你设置的这个值. 你可能会问为什么这里CXF不把客户端提交的密码传入让我们在 ServerPasswordCallbackHandler中比较呢.

WebService之JAX-WS、CXF、Spring3.0+

- - 博客园_首页
          面对工作的需要,web服务这一块一直都在身边转悠着. 既然工作中需要这些,作为程序员就应该去了解和学习. 下面主要简述采用CXF+Spring+JAX-WS来发布WebService服务,以及创建客户端调用服务.          1、先了解关于WebService的相关概念以及一些专有名词的解释:.

SOAP WebService以CXF实现WS-Security之xml签名及加密

- - 编程语言 - ITeye博客
接上篇,记录一下使用apache cxf和spring使用自签名数字证书实现WebService服务端及客户端的xml签名、加密以及解密和签名验证;. 这里仅针对客户端加密和签名并在服务端实现解密及签名验证的单向认证的情形,双向认证可以参照官方sample改进;. 客户端使用客户端私钥进行消息签名、客户端使用服务端公钥消息加密;.

Hessian, CXF, Spring httpinvoke 对比

- - Java - 编程语言 - ITeye博客
做了一个 Hessian, CXF, Spring httpinvoke 速度对比. 时间消耗  cxf > spring httpinvoke > hessian. 并发为10, 调用1W次所耗时间. 当然, 都知道 cxf 和 hessian 实现以及应用场景不太一样, 但差这么多还是很意外的.

webService学习之cxf与spring的简单整合

- - 企业架构 - ITeye博客
一:先把cxf的jar包导进去,我是直接在官网下载的cxf的包,解压后直接把lib文件夹里的jar一次.    性全部丢进去了,因为在学习,还不知道哪些包要哪些包不要的,所以干脆直接放进去. . . .

利用JAX-WS开发Web服务

- - CSDN博客推荐文章
利用JAX-WS开发Web服务.        Web服务是一种经由HTTP与其他软件进行通信的软件. Java最激动人心的一个特性是用于XML Web服务的Java API(JAX-WS). JAX-WS是一组Java类和包,他可以创建对Web服务发出请求的客户端,以及接受这些请求的服务.        JAX-WS支持使用简单对象访问协议(SimpleObject Access Protocol,SOAP)和表述性状态转移(Representational State Transfer,REST)实现的Web服务.

webservice编程基础—cxf

- - ITeye博客
最近研究了一下cxf的使用,主要的步骤如下:. 下载最新的cxf包apache-cxf-2.6.2.tar.zip,并解压,有一个lib文件,里面的jar包,就是webservice需要的(不完全需要,看你的应用,但是懒的分),加载进你的webservice的工程即可. 配置两个配置文件,为beans.xml和web.xml,内容如下:.

CXF WEBSERVICE 安全验证

- - 企业架构 - ITeye博客
CXF 封装的接口,不希望对外暴露 WSDL结构,找到的CXF安全认证技术都是基于拦截器,在调用的时候返回认证错误信息, 不能保护WSDL不被看到,后来看到别人的一个实现方式最简单有效,基于URL拦截的安全保护,用FILTER. 现在把这2种安全保护都记录下来,备用. 参考: http://www.myexception.cn/open-source/1505475.html.

CXF 入门:HelloWorld接口发布

- - ITeye博客
第一步:在myeclipse中新建一个web项目名为myWs,. 并导入依赖的jar包(cxf,spring,apache-commons相关). cxf结合spring时所需jar包,此例子也需要这些,用到了spring上下文加载. 第二步:在WEB-INF中创建基本的cxf-beans.xml内容如下(作用:主要做webservice接口属性配置,通过web.xml配置加载,文件名和位置可以顺便,web.xml配置会用到).

CXF+JAXB处理复杂数据

- - 博客园_首页
CXF+JAXB处理复杂数据. JAXB 来实现对象和XML之间的映射. 前面的例子 中,使用CXF发布的Webservice,其方法的参数和返回值都是简单类型. 本文讨论对象复杂性的分级,验证对于各种复杂度JAXB的支持情况,以及使用JAXB时对于Map,循环引用,继承等情况的处理办法. 文中的例子没有直接调用JAXB的API,而是用CXF发布webservice的形式验证对象到xml的marshal和unmarshal, 所以本文也可以作为使用CXF的参考资料.