- 浏览: 101296 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
wangyudong:
由CXF实现的微服务需要有比较好的工具去测试RESTful A ...
CXF 拦截器的使用(转) -
bayer05:
这种做法的缺陷在于对于每一个service的方法, 都要客户端 ...
cxf-rsa加密(记录)
CXF 拦截器的使用
在做SP短信管理平台开发时,需要连接电信ISAG短信网关,而电信ISAG短信网关提供WebService 短信提交服务,需要开发WebService客户端连接网关。开发时使用CXF技术为开发技术。
连接时,根据服务要求添加头信息,在头信息中增加验证信息,比如用户ID,加密密码,还有其他业务信息,类似下面的Demo代码:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<tns:RequestSOAPHeader
xmlns:tns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">
<tns:username xmlns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1" >
test_username
</tns:username>
<tns:password xmlns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">
b936443545b5061eceff663eadd8e91d
</tns:password>
<tns:timeStamp xmlns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">
1013135742
</tns:timeStamp>
</tns:RequestSOAPHeader>
</soap:Header>
<soap:Body>
<!-- 省略 -->
</soap:Body>
</soap:Envelope>
而SoapHeader信息使用拦截器,可以很容易添加,下面的Sample代码添加头信息:
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class SampleHeaderInterceptor extends AbstractSoapInterceptor {
private static String namespaceURI = "http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1";
public SampleHeaderInterceptor() {
super(Phase.WRITE);
}
public void handleMessage(SoapMessage message) throws Fault {
String timeStampStr = df.format(new Date());
String spPasswordStr = getSpPassword(System.getProperty("spId", ""), System.getProperty("spKey", "") );
QName qName = new QName("RequestSOAPHeader");
Document document = DOMUtils.createDocument();
Element spId = document.createElement("tns:spId");
spId.setTextContent(System.getProperty("spId", ""));
Element spPassword = document.createElement("tns:spPassword");
spPassword.setTextContent(spPasswordStr);
Element root = document.createElementNS(namespaceURI, "tns:RequestSOAPHeader");
root.appendChild(spId);
root.appendChild(spPassword);
SoapHeader header = new SoapHeader(qName, root);
List<Header> headers = message.getHeaders();
headers.add(header);
}
private static String getSpPassword(String spId, String key) {
try {
return MD5.md5((spId + key).getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
使用时,在配置文件中添加Out 拦截器,配置文件如下:
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="sample.service.SendSms" />
<property name="address" value="http://localhost:8080/service/sms/SendSmsService" />
<property name="outInterceptors">
<list>
<bean class="sample.client.SampleSOAPHeaderInterceptor" />
</list>
</property>
</bean>
也可以在代码中直接添加拦截器:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress("http://localhost:8080/service/sms/SendSmsService");
factory.setServiceClass(SendSms.class);
factory.getOutInterceptors().add(new sample.client.SampleSOAPHeaderInterceptor());
这样就可以完成Out拦截器了。
但接下来就遇到问题了,短信上行(回复),还有状态报告返回都会添加回访用户名和密码,(类似提交短信也要进行用户名密码验证,否则我们的接收平台会收到很多可能是别人无效的信息),于是获取用户名和密码的拦截器也需要开发,但是在开发读取拦截器时都无法获取头信息,弄了快一天都行,而任务要求时间紧,到网上Google 下,使用了Handler 处理机制进行了处理,代码如下:
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.apache.log4j.Logger;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SampleSoapAuthHandler implements Handler<SOAPMessageContext> {
private static Logger log = Logger.getLogger(SampleSoapAuthHandler.class);
private String spRevId;
private String spRevpassword;
public void close(MessageContext messageContext) {
log.info("SampleSoapAuthHandler close");
}
public boolean handleFault(SOAPMessageContext messageContext) {
log.error("handleFault error");
return false;
}
public boolean handleMessage(SOAPMessageContext messageContext) {
SOAPMessage message = messageContext.getMessage();
Boolean outboundProperty = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!outboundProperty) { // InBound Message,
String spRevId = "";
String spRevpassword = "";
try {
SOAPHeader soapHeader = message.getSOAPHeader();
NodeList nodeList = soapHeader.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node nodeAuth = nodeList.item(i);
if (nodeAuth.getNodeType() == Node.ELEMENT_NODE && "SampleSOAPHeader".equals(nodeAuth.getLocalName())) {
for (Node node = nodeAuth.getFirstChild(); node != null; node = node.getNextSibling()) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if ("spRevId".equals(node.getLocalName()) && node.getFirstChild() != null) {
spRevId = node.getFirstChild().getTextContent();
} else if ("spRevpassword".equals(node.getLocalName()) && node.getFirstChild() != null) {
spRevpassword = node.getFirstChild().getTextContent();
}
}
}
}
}
boolean ret = validUserAndPswd(spRevId, spRevpassword);
if (!ret) {
log.warn("错误的反调用户名和密码,spRevId:" + spRevId + ",spRevPassword:" + spRevpassword);
return ret;
}
log.info("收到信息,验证通过");
System.setProperty("mo:linkId", linkId);
return ret;
} catch (SOAPException e) {
log.error("解析异常,SOAPException:" + e, e);
}
}
return false;
}
private boolean validUserAndPswd(String spRevId, String spRevpassword) {
if(this.spRevId == null && this.spRevpassword == null)
return true;
if(this.spRevId == null && this.spRevpassword != null)
return this.spRevpassword.equals(spRevpassword);
if(this.spRevId != null && this.spRevpassword == null)
return this.spRevId.equals(spRevId);
return this.spRevId.equals(spRevId) && this.spRevpassword.equals(spRevpassword);
}
public void setSpRevId(String spRevId) {
this.spRevId = spRevId;
}
public void setSpRevpassword(String spRevpassword) {
this.spRevpassword = spRevpassword;
}
}
上述代码部分来自google 搜索到的,在此谢谢原作者。
添加处理器配置文件:
<bean id="isagReceiver" class="sample.SampleReceiver" singleton="false" >
<property name="address" value="http://localhost:8080/service/MessageService" />
<property name="handlers">
<list>
<ref bean="authHandler"/>
</list>
</property>
</bean>
<bean id="authHandler" class="sample.SampleSoapAuthHandler" singleton="true">
<property name="spRevId" value="username"></property>
<property name="spRevpassword" value="pawd"></property>
</bean>
因为自定义的处理器实现Handler接口,所以代码中只需要把自己的业务处理放在handler方法中即可,处理器链会自动调用。
终于可以完成任务了。
之后,有了空闲时间,对cxf的拦截器还是决定各种方式进行测试,今天终于得到满意的结果,把拦截验证的拦截器代码贴出来,如果有更好的建议,可以交流下:
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SpInfoInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private SAAJInInterceptor inInterceptor = new SAAJInInterceptor();
public SampleInterceptor() {
super(Phase.PRE_PROTOCOL);
getAfter().add(SAAJInInterceptor.class.getName()); //这一步好像是必须的,与 inInterceptor.handleMessage(message); 关联
}
public void handleMessage(SoapMessage message) throws Fault {
//此处注意 是javax.xml.soap.SOAPMessage 而不是 org.apache.cxf.binding.soap.SoapMessage
//虽然方法参数是SoapMessage
SOAPMessage sm = message.getContent(SOAPMessage.class);
if (sm == null) {
inInterceptor.handleMessage(message);
sm = message.getContent(SOAPMessage.class);
}
SOAPHeader header = null;
try {
header = sm.getSOAPHeader();
} catch (SOAPException e) {
e.printStackTrace();
}
if (header == null) {
return;
}
//获取<soap:Header ..><tns:RequestSOAPHeader ...> ... </tns:RequestSOAPHeader></soap:Header>中指定的标签的内容
NodeList nodeList = header.getElementsByTagName("tns:RequestSOAPHeader");
for (int i = 0; i < nodeList.getLength(); i++) {
Node nodeAuth = nodeList.item(i);
for (Node node = nodeAuth.getFirstChild(); node != null; node = node.getNextSibling()) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
//if("username".equals(node.getLocalName()) && node.getFirstChild() != null) {
// username = node.getFirstChild().getTextContent(); //获取<soap:Header> 中的username参数的值
//}
if (node.getLocalName() != null && node.getFirstChild() != null)
System.out.println(node.getLocalName() + " <===========> " + node.getFirstChild().getTextContent());
}
}
//}
}
}
}
上述部分代码也是参考网上代码,谢谢原作者。
代码中省略的日志信息的输出,可以自行添加。
至此, cxf 添加头信息和验证信息的两种拦截器都完成了,其他类似的功能的拦截器可以相互参考,其他的如附件的拦截器有空再补充了,今天就写到这里。
文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/java/javajs/20100106/186733.html
评论
之前习惯用一款名字为 WisdomTool REST Client,支持自动化测试RESTful API,输出精美的测试报告,并且自动生成精美的RESTful API文档。
轻量级的工具,功能却很精悍哦!
https://github.com/wisdomtool/rest-client
Most of REST Client tools do not support automated testing.
Once used a tool called WisdomTool REST Client supports automated testing, output exquisite report, and automatically generating RESTful API document.
Lightweight tool with very powerful features!
https://github.com/wisdomtool/rest-client
发表评论
-
20个开源项目托管站点推荐
2013-07-10 15:30 768开源中国社区收录了 ... -
soa技术,webservice,soap(转)
2011-10-05 01:04 1298SOA,现在进行时(摘抄 ... -
CXF 2.0 学习笔记-3 SOAP Header (转)
2011-09-21 00:48 9338CXF 2.0 学习笔记-3 SOAP Header 基 ... -
解析soap
2011-09-21 00:06 6005<?xml version= '1.0 ' en ... -
CXF处理不规则SOAP message(转)
2011-09-15 00:48 1413CXF处理不规则SOAP message ... -
webservice记录
2011-09-15 00:23 715http://blog.csdn.net/gytmtc/art ...
相关推荐
讲解了cxf实现拦截器的原因、核心API及使用方法
08.CXF拦截器的理论以及如何为CXF的客户端和服务器端添加拦截器
CXF使用EndpointImpl发布WebService加入拦截器
Cxf拦截器示例的源码,包含客户端和服务器端的内容。
CXF3.0 Spring3.2 自定义拦截器
11.为CXF客户端添加自定义拦截器完成权限控制
Web Service学习-CXF开发Web Service的权限控制(二)
spring4+cxf3,因为自己项目要用到接口开发,所以综合现有网上所有教程,终于成功写出能自动注入的demo,这个是含拦截器
10.为CXF服务器端添加自定义拦截器进行权限检查
webservice拦截器demo-服务端和调用端
CXF发布WebService加入拦截器
webservice的cxf框架拦截器demo.rar
13.为CXF与Spring整合发布WebService添加拦截器进行权限控制
包含表结构(mysql表创建语句),字段说明与使用;拦截器代码(可根据业务进行修改);
CXF 自定义拦截器实现的 webservice安全机制实例工程, 带jar包 ,代码注释详细 内有说明文档, 由于资源过大 ,所以客户端jar包 删除掉了, 只需要把服务端的jar 拷贝到 客户端即可 , 小弟刚刚研究完 CXF 安全 。...
CXF-拦截器-权限控制-登录校验
本文根据java代理实现CXF拦截器异常时只能进入fault拦截器而不能继续向下执行的问题。 利用java代理让RMI具有拦截器的功能。
注册自定义拦截器,添加拦截路径和排除拦截路径WebAppConfig
CXF spring 提供rest服务输出xml或json等格式数据
文中讲解了CXF服务端的库文件,文件配置要求;客户端、服务端的访问示例;CXF的整合;拦截器的使用;等CXF常用的操作。