CXF拦截器使用,创建一个使用SOAPHeader的安全验证
xml格式: <soap:Header> <auth:authentication xmlns:auth="http://gd.chinamobile.com//authentication"> <auth:systemID>1</auth:systemID> <auth:userID>test</auth:userID> <auth:password>test</auth:password> </auth:authentication> </soap:Header>
一,首先在服务端创建一个拦截器(被调用端),需要继承org.apache.cxf.phase.AbstractPhaseInterceptor 代码如下:
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.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.apache.log4j.Logger; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * 系统全局拦截器(排除登录服务调用) 用于校验登录的账号是否已登录 * */ public class AuthValidateInterceptor extends AbstractPhaseInterceptor<SoapMessage> { private Logger logger = Logger.getLogger(this.getClass()); public AuthValidateInterceptor() { // 定义拦截器阶段 super(Phase.PRE_INVOKE); } /** * @Description: 拦截器操作 * @param message * 被拦截到的消息 * @throws Fault */ @Override public void handleMessage(SoapMessage message) { List<Header> headers = message.getHeaders(); if (headers == null || headers.isEmpty()) { throw new Fault(new Exception("无授权信息!")); } Element auth = null; // 获取授权信息元素 for (Header header : headers) { QName qname = header.getName(); String tagName = qname.getLocalPart(); if (tagName != null && tagName.equals("auth")) { auth = (Element) header.getObject(); break; } } // 如果授权信息元素不存在,提示错误 if (auth == null) { throw new Fault(new Exception("无授权信息!")); } NodeList nameList = auth.getElementsByTagName("username"); NodeList pwdList = auth.getElementsByTagName("password"); if (nameList.getLength() != 1 || pwdList.getLength() != 1) { throw new Fault(new Exception("授权信息错误!")); } String name = nameList.item(0).getTextContent(); String password = pwdList.item(0).getTextContent(); if (!"admin".equals(name) || !"admin".equals(password)) { throw new Fault(new Exception("授权信息错误!")); } } }
二,修改cxf-beans.xml <!--id:随意配,implementor:指定接口具体实现类,address:随意配,访问时会用到,下面会做说明--> <!--拦截器--> <bean id="authIntercetpr" class="unitTest.AuthIntercetpr"></bean> <jaxws:endpoint id="HelloWorldService" implementor="com.ws.HelloWorldServiceImpl" address="/IHelloService"> <!-- 在此配置调用当前ws所触发的拦截器--> <jaxws:inInterceptors><ref bean="authIntercetpr" /></bean> <!--或者直接在这里写<bean class="unitTest.AuthIntercetpr"></bean>--> </jaxws:inInterceptors> </jaxws:endpoint> 到此服务端工作完毕!!! 下面是客户端(调用端) 三,这边同样创建一个拦截器,实现org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor
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.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * 系统全局拦截器(排除登录服务调用) 用于校验登录的账号是否已登录 * */ public class ClientAuthValidateInterceptor extends AbstractSoapInterceptor { private Logger logger = Logger.getLogger(this.getClass()); public static final String xml_namespaceUR = ""; public static final String xml_header = "soap:Header"; public static final String xml_authentication = "auth:authentication"; public static final String xml_systemID = "auth:systemID"; public static final String xml_username = "auth:username"; public static final String xml_password = "auth:password"; public ClientAuthValidateInterceptor() { // 定义拦截器阶段 super(Phase.WRITE); } /** * @Description: 拦截器操作 * @param message * 被拦截到的消息 * @throws Fault */ @Override public void handleMessage(SoapMessage message) { String userId = "test"; String sysId = "1"; String password = "test"; Document doc = DOMUtils.createDocument(); Element root = doc.createElement(xml_header); Element eSysId = doc.createElement(xml_systemID); eSysId.setTextContent(sysId); Element eUserId = doc.createElement(xml_username); eUserId.setTextContent(userId); Element ePwd = doc.createElement(xml_password); ePwd.setTextContent(password); Element child = doc.createElementNS(xml_namespaceUR, xml_authentication); child.appendChild(eSysId); child.appendChild(eUserId); child.appendChild(ePwd); root.appendChild(child); QName qname = new QName("RequestSOAPHeader"); SoapHeader head = new SoapHeader(qname, root); List<Header> headers = message.getHeaders(); headers.add(head); } }
四,具体调用ws的类代码
HelloWorldServiceImplService hello = new HelloWorldServiceImplService(); HelloWorldService service = hello.getHelloWorldServiceImplPort(); // 插入身份验证 Client clientProxy = ClientProxy.getClient(port);// 通过目标ws获取代理 // 注入拦截器,getOutInterceptors代表调用服务端时触发,getInInterceptors就是被调用才触发 clientProxy.getOutInterceptors().add(new ClientAuthValidateInterceptor()); // 超时时间设置 HTTPConduit http = (HTTPConduit) clientProxy.getConduit(); HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); httpClientPolicy.setConnectionTimeout(Integer.valueOf("6000")); httpClientPolicy.setReceiveTimeout(Integer.valueOf("6000")); httpClientPolicy.setAllowChunking(false); http.setClient(httpClientPolicy); //下面这行代码是具体调用服务段的deleteTeskTask() CallResult cResult = service.deleteTeskTask("1223");
五,还有一种方式是通过JaxWsProxyFactoryBean方式,注册拦截器及实例化ws,代码如下:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); List<Interceptor<? extends Message>> clientAuthValidateInterceptors = new ArrayList<>(); // 添加soap header 信息 clientAuthValidateInterceptors.add(new ClientAuthValidateInterceptor()); // 注入拦截器,getOutInterceptors代表调用服务端时触发,getInInterceptors就是被调用才触发 factory.setOutInterceptors(clientAuthValidateInterceptors); factory.setServiceClass(HelloWorldService.class);// 实例化ws factory.setAddress("http://localhost:8090/iwm/sapDeliveryOrderToIwm"); Object obj = factory.create(); HelloWorldService service = (HelloWorldService) obj; //下面这行代码是具体调用服务段的deleteTeskTask() CallResult cResult = service.deleteTeskTask("1223");
客户端代码到此结束