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

Posted 如若

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CXF 入门:创建一个基于SOAPHeader的安全验证(CXF拦截器使用)相关的知识,希望对你有一定的参考价值。

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");
客户端代码到此结束

以上是关于CXF 入门:创建一个基于SOAPHeader的安全验证(CXF拦截器使用)的主要内容,如果未能解决你的问题,请参考以下文章

CXF 入门:创建一个基于WS-Security标准的安全验证(CXF回调函数使用)

java webservice 如何在服务端设置相应的soapheader

java调用webservice怎么添加 SoapHeader 做验证

C#在做WSDL生成客户端代码,无法添加soapheader

基于CXF框架下的SOAP Webservice服务端接口开发

请教一个python调用webservice时进行soapheader认证的问题