CXF动态客户端调用JDK自带Webservice安全校验

原创 2015年11月17日 18:13:03

        项目中有个需求,需要使用CXF动态客户端调用webservice服务端,这个服务端是JDK自带的webservice发布的,而且我们需要在调用时传入用户名和密码。网上CXF客户端和服务端配套使用webservice的方法很多,这里不再赘述,这里主要讲下我上边说的特殊使用方式。有人会把用户名和密码放在webservice的请求参数里,这样污染了webservice接口,本人不喜欢这种方式。

        开始的时候,我先试了CXF拦截器传送密码的方式,我自己是参照类似的文章写的:点击打开链接,结果发现出现很多奇怪的错误,比如各种命名空间不识别,JAXB解组错误等等,压根就没有进入服务端的handler,当然了服务端的总入口也是拿到了请求,只是在进入handler之前就报错了。按说CXF也是遵守了webservice的国际规范了应该可以的。后来看了CXF中的传入用户名和密码所涉及的类和参数,分析出CXF应该是对SOAP的head操作做了封装,所以导致SOAP中的具体数据内容和JDK自带的webservice是不同的,怎么办呢?后来想到我可以直接自定义SOAP头,然后到服务端的handler中拿到这个头进行分析不就解决了?经过各种调试,终于解决了。下边公布代码:

        1、服务端的handlers.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
             <handler-chain>
               <handler>
                  <handler-name>ServiceSOAPHandler</handler-name>
                  <handler-class>com.cms.webservice.AuthorityHandler</handler-class>
              </handler>
            </handler-chain>
            </handler-chains>

       2、服务端的handler代码:

    /**
     * 
     */
    package com.cms.webservice;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Set;
    
    import javax.xml.namespace.QName;
    import javax.xml.soap.Node;
    import javax.xml.soap.SOAPBody;
    import javax.xml.soap.SOAPConstants;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPFault;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    import javax.xml.ws.soap.SOAPFaultException;
    
    import com.jeecms.cms.Constants;
    import com.jeecms.common.util.PropertyUtils;
    
    /**
     * 服务端权限校验类
     * 
     * @author zhaichong
     *
     *         2014年10月1日
     */
    public class AuthorityHandler implements SOAPHandler<SOAPMessageContext> {
    
    private static String PROPERTIE_NAME="webservice.properties";
    private static String USER_NAME_PWD="webservice.userNamePwd";
   
    public boolean handleMessage(SOAPMessageContext context) {
    return auth(context);
    }
    
    /**
    * 校验用户名密码是否合法
   
    * @param context
    * @return
    */
    private boolean auth(SOAPMessageContext context) {
    Boolean out = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (!out) {
    SOAPMessage message = context.getMessage();
    try {
    SOAPHeader header = message.getSOAPPart().getEnvelope().getHeader();
    if (header != null) {
    // 获取SOAP头登录校验节点
    // org.w3c.dom.Node node =
    // header.getElementsByTagName("authHeader").item(0);
    // 获取用户名
    org.w3c.dom.Node userNameNode = header.getElementsByTagName("userName").item(0);
    String userName = userNameNode.getTextContent();
    // 获取密码
    org.w3c.dom.Node passwordNode = header.getElementsByTagName("password").item(0);
    String password = passwordNode.getTextContent();
    // 获取本地配置文件用户名密码 与传过来的用户名密码比对
    PropertiesUtil propertiesUtil = new PropertiesUtil(PROPERTIE_NAME);
    String userNamePWD = propertiesUtil.getKeyValue(USER_NAME_PWD);
    if (userNamePWD != null) {
    String namePWDs[] = userNamePWD.split(",");
    for (int i = 0; i < namePWDs.length; i++) {
    if (namePWDs[i] != null) {
    String uName = namePWDs[i].split("\\|")[0];
    String uPassword = namePWDs[i].split("\\|")[1];
   
    if (uPassword.equals(password) && uName.equals(userName)) {
    return true;
    }
    }
    }
    }
    //System.out.println("client send userName:" + userName);
    //System.out.println("client send password:" + password);
    return false;
    } else {
    return false;
    }
    } catch (SOAPException e) {
    e.printStackTrace();
    }
    
    }
    
    return true;
    }
    
    public boolean handleFault(SOAPMessageContext context) {
    // TODO Auto-generated method stub
    return false;
    }
    
    public void close(MessageContext context) {
    // TODO Auto-generated method stub
    
    }
    
    public Set<QName> getHeaders() {
    // TODO Auto-generated method stub
    return null;
    }
    
    }

   注意: 这里的handler.xml文件在war包里是放在classes下的,webservice的实现类要用@HandlerChain(file="handlers.xml")进行注解,上边代码的用户名和密码是放在properties文件中的,各位网友可以自己修改。

3、客户端的拦截器:

    package gboat2.cxf.test;


    import gboat2.cxf.utils.AuthorityParameter;
    
    import java.util.List;
    
    import javax.xml.namespace.QName;
    
    import org.apache.cxf.binding.soap.SoapMessage;
    import org.apache.cxf.headers.Header;
    import org.apache.cxf.helpers.DOMUtils;
    import org.apache.cxf.interceptor.Fault;
    import org.apache.cxf.phase.AbstractPhaseInterceptor;
    import org.apache.cxf.phase.Phase;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    /**
     * <p>
     * 调用webservice时需要传入用户名和密码
     * </p>
     *
     */
    public class AuthorityHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{  
        private AuthorityParameter authorityParameter;
        public AuthorityHeaderInterceptor(AuthorityParameter authorityParameter) {  
            super(Phase.PREPARE_SEND);  
            this.authorityParameter = authorityParameter;
        }   
        
        public void handleMessage(SoapMessage msg) throws Fault {    
            List<Header> headers = msg.getHeaders();  
            //创建Document对象  
            Document doc = DOMUtils.createDocument();  
    
            //配置服务器端Head信息的用户密码  
            Element eleId= doc.createElement(this.authorityParameter.getUserNameKey());  
            eleId.setTextContent(this.authorityParameter.getUserNameValue());  
            Element elePass = doc.createElement(this.authorityParameter.getPasswordKey());  
            elePass.setTextContent(this.authorityParameter.getPasswordValue());   
            /** 
             * 也可以先创建一个父节点,则生成的XML文档 ,我们这里是直接使用用户名和密码
             * <authHeader> 
             *      <userId>lzw</userId> 
             *      <userPass>123456</userPass> 
             * </authHeader> 
             */  
            headers.add(new Header(new QName(""), eleId));  
            headers.add(new Header(new QName(""), elePass)); 
        }   
    }  

    4、用户名和密码类:

        
    package gboat2.cxf.utils;
    
    
    public class AuthorityParameter {
    /**
    * 用户名字段的名称
    */
    private String userNameKey;
   
    /**
    * 用户名字段的值
    */
    private String userNameValue;
   
    /**
    * 密码字段的名称
    */
    private String passwordKey;
   
    /**
    * 密码字段的值
    */
    private String passwordValue;
   
    public AuthorityParameter() {
    super();
    }
   
    /**  
    * AuthorityParameter
    * @param userNameKey 用户名的字段名称
    * @param userNameValue 用户名的字段值
    * @param passwordKey 密码的字段名称
    * @param passwordValue 密码的字段值
    */
    public AuthorityParameter(String userNameKey, String userNameValue, String passwordKey, String passwordValue) {
    super();
    this.userNameKey = userNameKey;
    this.userNameValue = userNameValue;
    this.passwordKey = passwordKey;
    this.passwordValue = passwordValue;
    }
    
    public String getUserNameKey() {
    return userNameKey;
    }
    
    public void setUserNameKey(String userNameKey) {
    this.userNameKey = userNameKey;
    }
    
    public String getUserNameValue() {
return userNameValue;
}


public void setUserNameValue(String userNameValue) {
this.userNameValue = userNameValue;
}


public String getPasswordKey() {
return passwordKey;
}


public void setPasswordKey(String passwordKey) {
this.passwordKey = passwordKey;
}


public String getPasswordValue() {
return passwordValue;
}


public void setPasswordValue(String passwordValue) {
this.passwordValue = passwordValue;
}
   }

    5、调用代码

   JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); 
   Client client = null; 
   // 创建客户端连接 
   client = factory.createClient("http://localhost:9090/cms/saveCms?wsdl"); 

   AuthorityParameter param = new AuthorityParameter("userName", "anshun", "password", "123456");
   client.getOutInterceptors().add(new AuthorityHeaderInterceptor(authorityParameter)); 
   client.getOutInterceptors().add(new LoggingOutInterceptor()); 

   // 客户端设置

   HTTPClientPolicy policy = ((HTTPConduit) client.getConduit()).getClient();
   policy.setConnectionTimeout(30000);
   policy.setReceiveTimeout(180000);

   // 以下就是具体调用方法,这里不写了,网上很多。

   ......

   好了,这样在服务端就能获取到用户名和密码,又不会污染webservice的方法参数。记下来防止遗忘,也为各位网友解决这种问题提供个思路,网上这种资料太少了。其中的部分代码是从项目代码里摘录出来的,可能有的地方有纰漏,但是思路脉络已经清除了,希望能帮到各位网友。另外,如果有需要了解JDK自带webservice如何使用用户名和密码来进行调用前的校验,可以参考我的一个例子:点击打开链接

                

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

java客户端动态调用webservice服务

之前调用webservice服务一直用jdk或者eclipse快速生成客户端代码,这种方式实现起来也比较容易,据说这种方法执行效率也是最好的(动态调用也会动态生成客户端代码)。但是我最近在项目发现这种...

CXF客户端开发--动态调用webservice

之前关于webservice的文章中已经介绍了CXF JAX-WS proxy客户端模式。JAX-WS proxy模式需要在客户端使用wsdl2java生成代理接口,这种方式相对于动态调用,其效率相对...
  • lkx94
  • lkx94
  • 2014-12-09 13:55
  • 1433

利用JDK开发WebService简单实现

开发环境: eclipse+JDK8 首先开发服务器端: 1.定义SEI接口和其实现类 2.发布webservice 目录结构如下 ①SEI接口:HelloWs.javapackage c...

WebService与Spring整合《三》

问题?WebService与Spring整合过程 前面的的提到了WebService整体开发过程,这里主要是说WebService与Spring的整合过程 一、提出问题 问题:在以往的项目中,...

WebService CXF调用方式《三》

问题?WebService CXF调用方式《三》,CXF工作原理和调用方式 一、CXF是什么? Apache CXF是一个开源的,全功能的,容易使用的Web服务框架。CXF是两个项目的结合:由IO...

c++标准库——命名空间std和头文件的演变

1、命名空间stdC++标准中引入命名空间的概念,是为了解决不同模块或者函数库中相同标识符冲突的问题。有了命名空间的概念,标识符就被限制在特定的范围呢,不会引起命名冲突。最典型的例子就是std命名控件...

CXF动态客户端调用webservice实例

使用CXF实现WebService,并在客户端实现动态调用编写服务器注意事项 注意 :不要指定 @SOAPBinding(style=Style.RPC, use=Use.LITERAL)...

CXF生成调用webservice的客户端

首先当前是从官网下载cxf组件. http://cxf.apache.org/download.html    下载后解压,在这里主要是用到解压后的bin目录中的wsdl2java.ba...

客户端利用CXF中的JaxWsProxyFactoryBean 对webservice地址进行调用

其实调用代码关键就简单几行 一个实现类,一个引用接口、接口主要指定需要调用的webservice地址中的方法、参数、返回类型的配置 public Object webserviceRequest(...

java调用基于SOAP的CXF 框架的WebService客户端和服务器段helloworld例子

依赖的JAR     cxf-2.2.10.jar     jetty-6.1.21.jar     jetty-util-6.1.21.jar   &...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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