整体需求是这样的,作为服务端,我的接口需要有一个安全验证,因此做了一个拦截器来验证soapHeader。作为客户端,需要往soapHeader中添加双方规定的参数。搞了一天多,在网上看了很多方法,最终还是搞定了。不得不说,现在网上的抄袭现象太严重了,有的博客甚至把别人分享的东西搬过来,连一个字都不带改的……
服务端拦截器验证soapHeader
服务端主要是spring,接口是通过CXF发布的,贴一下spring配置文件代码
<bean id="SendDataService" class="com.ipt.webservice.send.impl.SendDataServiceImpl" />
<jaxws:endpoint id="sendData" implementor="#SendDataService"
address="/sendData" >
<!-- 加入拦截器 -->
<jaxws:inInterceptors>
<bean class="com.ipt.filter.WebServiceInterceptor"></bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
然后需要写一个拦截器 (WebServiceInterceptor),该类需要继承 AbstractPhaseInterceptor
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.ipt.util.CommonUtil;
public class WebServiceInterceptor extends
AbstractPhaseInterceptor<SoapMessage> {
public WebServiceInterceptor() {
super(Phase.PRE_INVOKE);
}
public void handleMessage(SoapMessage soapMsg) throws Fault {
List<Header> headers = soapMsg.getHeaders();// 根据soap消息获取头部
if (headers == null || headers.size() == 0) {
throw new Fault(new IllegalArgumentException("拒绝访问,原因:没有header!"));
}
for (Header header : headers) {
Element ele = (Element) header.getObject();
NodeList nodeList = ele.getElementsByTagName("entryStr");
if (nodeList == null || nodeList.getLength() == 0) {
throw new Fault(new IllegalArgumentException("拒绝访问,原因:通行信息为空!"));
}
String entryStr = nodeList.item(0).getTextContent();
if (StringUtils.isNotBlank(entryStr)) {
boolean entryFlag = CommonUtil.validRequestClient(entryStr);
if (!entryFlag) {
throw new Fault(new IllegalArgumentException(
"拒绝访问,原因:通行信息验证未通过!"));
}
} else {
throw new Fault(new IllegalArgumentException("拒绝访问,原因:通行信息为空!"));
}
}
}
}
这样服务端的验证功能就完成了。
首先我们通过soapUI工具来验证一下接口
失败示例1:
失败示例2:
成功示例:
服务器端的验证已经没有问题了,最重要的是要有soapHeader,并且header中的格式应为 <check><entryStr>value</entryStr></check>,接下来我们看客户端。
CXF客户端添加soapHeader
我的客户端是通过 wsdl2java 工具生成的,其中有一个小插曲,我一开始下载了apache-cxf-3.3.2,但是一直报错(Unsupported major.minor version 52.0),应该是这个版本需要JDK1.7,但是我环境变量配的是jdk1.7,后来又下载了apache-cxf-3.1.15 就没问题了。下载完成后需要配置一下环境变量,然后就能生成代码了,然后新建一个java项目,把生成的代码拷贝到项目中。
接下来需要写一个添加soapHeader的类,再调用服务端的方法之前先添加header
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;
/**
* 添加soapHeader
*/
public class ClientCheckInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
public static final String ENTRY_STR = "123456admin";
public ClientCheckInterceptor() {
super(Phase.PREPARE_SEND);
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
List<Header> headers = message.getHeaders();
Document document = DOMUtils.createDocument();
Element checkEle = document.createElement("check");
Element entryStrEle = document.createElement("entryStr");
entryStrEle.setTextContent(ENTRY_STR);
checkEle.appendChild(entryStrEle);
headers.add(new Header(new QName(""),checkEle));
}
}
接下来写测试类 ServiceTest.java
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import com.ipt.webservice.send.SendDataService;
import com.ipt.webservice.send.impl.SendDataServiceImplService;
public class ServiceTest {
public static void main(String[] args) {
SendDataServiceImplService service = new SendDataServiceImplService();
SendDataService port = service.getSendDataServiceImplPort();
//添加soapHeader
Client client = ClientProxy.getClient(port);
client.getOutInterceptors().add(new ClientCheckInterceptor());
//调用服务端发布的方法
String task = port.queryCommittee();
System.out.println(task);
}
}
最后右键-run,测试一下是否能通过验证。控制台打印信息如下,访问成功
客户端中我用到了两个jar包:cxf-2.4.3.jar 和 cxf-manifest.jar
客户端代码(含客户端代码 + jar包 + apache-cxf-3.1.15)