【第22期】观点:IT 行业加班,到底有没有价值?

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如何使用用户名和密码来进行调用前的校验,可以参考我的一个例子:点击打开链接

                

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

相关文章推荐

webservice加密,通过SoapHeader来增强Web Service的安全性

(通常webservice 加密都是加Token.其实就是在SOAP包的包头里面加个用户名和密码... 在C#封完包后,操作包头好了)   7.9  如何保证Web Service的安全 要以...
  • yl_99
  • yl_99
  • 2013-03-13 13:51
  • 1274

Java调用带SoapHeader头验证的.net Webservice示例代码

private final static String endpoint = "http://172.29.12.125:101/AxionPosService.asmx"; public ...

Java 调用Web service 添加认证头(soapenv:Header)

有时候调用web service 会出现 Message does not conform to configured policy [ AuthenticationTokenPolicy(S) ]...

spring cxf 注解和头部验证

转载自:http://canken007.iteye.com/blog/1729547     http://www.blogjava.net/zljpp/archive/2012/04/15/374...

Cxf Webservice安全认证

在开发的时候发布webservice,为了安全通常需要安全验证,在CXF中的实现,在这里记录一下。   CXF是啥 我就不介绍了, 开发CXF+Spring的webservice服务: ...

动态调用WebService(支持SaopHeader)

动态调用WebService(支持SaopHeader) using System; using System.CodeDom; using System.CodeDom.Compiler; usin...

CXF 入门:CXF拦截器使用,创建一个基于SOAPHeader的安全验证

ader的安全验证 xml格式: cation xmlns:auth="http://gd.chinamobile.com//authentication"> 1 test test ...

CXF动态客户端的一些原理性知识总结

所谓的CXF动态客户端,是不需要使用wsdl2java工具去我们的源码里生成java客户端存根代理而已,但是实际上也是需要生成的,这个在CXF的类DynamicClientFactory原来里是可以看...

CXF客户端动态调用

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

CXF之动态客户端实例

通常创建一个web服务的客户端包括SEI的java接口和客户端输入输出应用的一些java类,这不总是可取的或实用的。 CXF支持不同的选择,允许一个应用连接到服务而不使用SEI和一些数据类。本页面介...
  • fhd001
  • fhd001
  • 2010-07-31 20:29
  • 9820
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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