CXF拦截器之数据校验(添加额外的Soap头信息)

本节内容概述

使用CXF拦截器实现在消息发送阶段添加额外的Soap头信息以及在接收阶段添加自定义的数据有效性校验拦截器。

本案例将实现的功能如下

  1. 在发送的Soap请求中加入soap:Header(默认情况下cxf并不会加入头信息,而且头信息不会影响到webservice的处理)。添加一套自定义的校验数据规则。
  2. 数据接收方,也就是Webservice的发布方可以通过添加拦截器在调用Webservice服务前进行头部的校验,从而保证数据的有效性。

以下提供更新安全的Webservice构想(菜鸟的思维)

上面的思路进行数据的加密。如果有人拦截到报文虽然无法伪造(因为我们做了头校验,当然也不是完全不能伪造,假设而已)但是他依然可以看懂报文内容,所以还应该将数据进行加密|解密,这样即使数据被拦截,他也不能理解我们传递的信息是什么。如果在加上一个用户认证功能也许就更perfect,这样我们的服务就可以细分的权限级别。
最终我们应该做到:数据被截获了,但是我们有头部校验啊(你伪造不了),我们数据有加密(你看不懂),我们有用户权限控制(你还要破解用户信息)。
三层防护,哈哈哈!!!

下面是头部校验代码一览
服务端:响应头包装,请求头解析

/**
 * 响应头包装器【服务器端--发送】
 * @author xbz
 *
 */
public class WebserviceResponseHeaderWrapper extends AbstractPhaseInterceptor<SoapMessage> {

    public WebserviceResponseHeaderWrapper(){
        super(Phase.PREPARE_SEND);
    }

    @Override
    public void handleMessage(SoapMessage soapMsg) throws Fault {
        System.out.println("ID:"+getId()+"服务器端--响应头包装器");
        List list =soapMsg.getHeaders();
        SoapHeader responsetHeader=WebServiceHeaderUtil.createResponsetHeader();
        list.add(0,responsetHeader);
    }
}
/**
 * 请求头解析器【服务器端--接收】
 * @author xbz
 *
 */
public class WebServiceRequestHeaderParser  extends AbstractPhaseInterceptor<SoapMessage> {
    public WebServiceRequestHeaderParser(){
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage soapMsg) throws Fault {
        System.out.println("服务器端--请求头解析器");
        List<Header> headers = soapMsg.getHeaders();
        Header header=null;
        if(headers==null||headers.size()==0){
            throw new Fault(new Exception("没有检查到请求头"));
        }else{
            header=headers.get(0);
        }
        Element element=(Element) header.getObject();
        NodeList idNodeList = element.getElementsByTagName(WebServiceHeaderUtil.REQUEST_HEADER_TAGETNAME_ID);
        NodeList timeNodeList = element.getElementsByTagName(WebServiceHeaderUtil.REQUEST_HEADER_TAGETNAME_TIME);
        NodeList codeNodeList = element.getElementsByTagName(WebServiceHeaderUtil.REQUEST_HEADER_TAGETNAME_CODE);
        if(idNodeList==null||idNodeList.getLength()==0){
            throw new Fault(new Exception("没有找到"+WebServiceHeaderUtil.REQUEST_HEADER_TAGETNAME_ID));
        }else if(timeNodeList==null||timeNodeList.getLength()==0){
            throw new Fault(new Exception("没有找到"+WebServiceHeaderUtil.REQUEST_HEADER_TAGETNAME_TIME));
        }else if(codeNodeList==null||codeNodeList.getLength()==0){
            throw new Fault(new Exception("没有找到"+WebServiceHeaderUtil.REQUEST_HEADER_TAGETNAME_CODE));
        }
        String request_id=idNodeList.item(0).getTextContent();
        String request_time=timeNodeList.item(0).getTextContent();
        String request_code=codeNodeList.item(0).getTextContent();
        boolean validateFlag = WebServiceHeaderUtil.validateHeader(request_id,request_time,request_code);
        if(!validateFlag ){
            throw new Fault(new Exception("请求头信息无效"));
        }
        System.out.println("=========================================================");

    }
}

服务端配置cxf-servlet

    <!--服务端发布  -->
    <jaxws:endpoint id="helloWorld" implementor="com.ainoties.core.webservice.sample.impl.HelloCXFImpl" address="/HelloWorld">
        <jaxws:inInterceptors>
            <ref bean="loggingInInterceptor"/>
            <ref bean="webserviceRequestHeaderParser"/>
        </jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <ref bean="loggingOutInterceptor"/>
            <ref bean="webserviceResponseHeaderWrapper"/>
        </jaxws:outInterceptors>
    </jaxws:endpoint>

客户端:请求头包装,响应头解析

/**
 * 请求头包装器【客户端--发送】
 * @author Administrator
 *
 */
public class WebServiceRequestHeaderWrapper extends AbstractPhaseInterceptor<SoapMessage> {
    public WebServiceRequestHeaderWrapper(){
        super(Phase.PREPARE_SEND);
    }

    @Override
    public void handleMessage(SoapMessage soapMsg) throws Fault {
        System.out.println("ID:"+getId()+"客户端-请求头包装器");
//      QName wsdl_service=(QName) message.getContextualProperty(Message.WSDL_SERVICE);
//      Object wsdl_port= message.getContextualProperty(Message.WSDL_PORT);
//      Object wsdl_port= message.getContextualProperty(Message.PROTOCOL_HEADERS);
//      QName q=new QName(namespaceURI, localPart, prefix);
//      Assert.isInstanceOf(SoapMessage.class, message);
        System.out.println("==========准备创建SoapHeader====================");
        List list =soapMsg.getHeaders();
        SoapHeader reuqestHeader=WebServiceHeaderUtil.createRquestHeader();
        list.add(0,reuqestHeader);
    }   
}
/**
 * 响应头包解析器【客户端--接收】
 * @author xbz
 *
 */
public class WebserviceResponseHeaderParser extends AbstractPhaseInterceptor<SoapMessage> {
    public WebserviceResponseHeaderParser(){
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage soapMsg) throws Fault {
        System.out.println("客户端--响应头包解析器");
        List<Header> headers = soapMsg.getHeaders();
        Header header=null;
        if(headers==null||headers.size()==0){
            throw new Fault(new Exception("没有检查到头信息"));
        }else{
            header=headers.get(0);
        }
        Element element=(Element) header.getObject();
        NodeList idNodeList = element.getElementsByTagName(WebServiceHeaderUtil.RESPONSE_HEADER_TAGETNAME_ID);
        NodeList timeNodeList = element.getElementsByTagName(WebServiceHeaderUtil.RESPONSE_HEADER_TAGETNAME_TIME);
        NodeList codeNodeList = element.getElementsByTagName(WebServiceHeaderUtil.RESPONSE_HEADER_TAGETNAME_CODE);
        if(idNodeList==null||idNodeList.getLength()==0){
            throw new Fault(new Exception("没有找到"+WebServiceHeaderUtil.RESPONSE_HEADER_TAGETNAME_ID));
        }else if(timeNodeList==null||timeNodeList.getLength()==0){
            throw new Fault(new Exception("没有找到"+WebServiceHeaderUtil.RESPONSE_HEADER_TAGETNAME_TIME));
        }else if(codeNodeList==null||codeNodeList.getLength()==0){
            throw new Fault(new Exception("没有找到"+WebServiceHeaderUtil.RESPONSE_HEADER_TAGETNAME_CODE));
        }
        String response_id=idNodeList.item(0).getTextContent();
        String response_time=timeNodeList.item(0).getTextContent();
        String response_code=codeNodeList.item(0).getTextContent();
        boolean validateFlag = WebServiceHeaderUtil.validateHeader(response_id,response_time,response_code);
        if(!validateFlag ){
            throw new Fault(new Exception("响应头信息无效"));
        }
        System.out.println("=========================================================");
    }
}

最重要的还有工具类,请使用DOMUtil(cxf旗下)进行xml元素操作

/**
 * 创造WebService的SoapHeader,以及加密|解密头信息
 * @author xbz
 *
 */
public class WebServiceHeaderUtil {
    public static DateFormat DATE_FORMAT=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    public static String DEFAULT_ENCODING="UTF-8";
    public static int MAX_SALT=100;//最大盐值MAX_SALT-1
    public static int DEFALUT_SALT=50;//当盐值为0时,取默认值
    public static QName REQUEST_HEADER_QNAME=new QName("RequestHeader", "http://sechemas.xml.ainotest.com/RequestHeader/");
    public static QName RESPONSE_HEADER_QNAME=new QName("ResponseHeader", "http://sechemas.xml.ainotest.com/ResponseHeader/");
    /*--------------标签名----------------------------*/
    public static String REQUEST_HEADER_TAGETNAME_ID="request_id";
    public static String REQUEST_HEADER_TAGETNAME_TIME="request_time";
    public static String REQUEST_HEADER_TAGETNAME_CODE="request_code";
    public static String RESPONSE_HEADER_TAGETNAME_ID="response_id";
    public static String RESPONSE_HEADER_TAGETNAME_TIME="response_time";
    public static String RESPONSE_HEADER_TAGETNAME_CODE="response_code";
    /**
     * 创造请求头信息
     * @return 返回构建好的xml
     */ 
    public static SoapHeader createRquestHeader(){
        SoapHeader header=null;
        try{
            String reqeustId=UUID.randomUUID().toString(); 
            String requestTime=DATE_FORMAT.format(new Date());
            String requestCode=createCode(reqeustId, requestTime);
            Document doc = DOMUtils.createDocument();
            Element root=doc.createElement("ainotes:RequestHeader");
            root.setAttribute("xmlns:ainotes", "http://sechemas.xml.ainotest.com/RequestHeader/");
            Element idEle=doc.createElement(REQUEST_HEADER_TAGETNAME_ID);
            idEle.setTextContent(reqeustId);
            Element timeEle=doc.createElement(REQUEST_HEADER_TAGETNAME_TIME);
            timeEle.setTextContent(requestTime);
            Element codeEle=doc.createElement(REQUEST_HEADER_TAGETNAME_CODE);
            codeEle.setTextContent(requestCode);
            root.appendChild(idEle);
            root.appendChild(timeEle);
            root.appendChild(codeEle);
            header=new SoapHeader(REQUEST_HEADER_QNAME,root);
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            return header;
        }
    }
    public static SoapHeader createResponsetHeader() {
        SoapHeader header=null;
        try{
            String reqeustId=UUID.randomUUID().toString(); 
            String reponseTime=DATE_FORMAT.format(new Date());
            String reponseCode=createCode(reqeustId, reponseTime);
            Document doc = DOMUtils.createDocument();
            Element root=doc.createElement("ainotes:ReponseHeader");
            root.setAttribute("xmlns:ainotes", "http://sechemas.xml.ainotest.com/ReponsetHeader/");
            Element idEle=doc.createElement(RESPONSE_HEADER_TAGETNAME_ID);
            idEle.setTextContent(reqeustId);
            Element timeEle=doc.createElement(RESPONSE_HEADER_TAGETNAME_TIME);
            timeEle.setTextContent(reponseTime);
            Element codeEle=doc.createElement(RESPONSE_HEADER_TAGETNAME_CODE);
            codeEle.setTextContent(reponseCode);
            root.appendChild(idEle);
            root.appendChild(timeEle);
            root.appendChild(codeEle);
            header=new SoapHeader(RESPONSE_HEADER_QNAME,root);
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            return header;
        }
    }
    /**
     * 根据id和time得到一个加密的code
     * @param id
     * @param time
     * @return
     */
    public static  String createCode(String id,String time){
        id=id.replace("-", "");
        String requestCode=null;
        try{
            int salt = getSalt(time);
            requestCode=encodeRequestId(id, salt);
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            return requestCode;
        }
    }
    public static int getSalt(String requestTime) {
        String s =requestTime.replaceAll("[\\.\\-\\s:]+", "");
        int ss=Math.abs(s.hashCode());
        int salt=ss%MAX_SALT;
        if(salt==0){
            salt=DEFALUT_SALT;
        }
        return salt;
    }
    public static String  encodeRequestId(String requestId,int salt) {
        String res=null;
        try{
            byte[] b=requestId.getBytes(DEFAULT_ENCODING);
            int end=salt-1;
            for (int i = 0; i < salt; i++) {
                if(i!=end){
                    b=DigestUtils.md5Digest(b);
                }else{
                    res=DigestUtils.md5DigestAsHex(b);
                }
            }
            res=res.replaceAll("[\\D]+", "");
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            return res;
        }
    }

    public static boolean validateHeader(String id, String time, String code) {
        Assert.notNull(id,"id不能为Null");
        Assert.notNull(time,"time不能为Null");
        Assert.notNull(code,"code不能为Null");
        return code.equals(createCode(id, time));
    }

测试方法:

    @Test
    public void testCXFClientWithInterceptor() throws Exception{
            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); 
            URL url= new URL("http://localhost:8080/cxf/webservice/HelloWorld?wsdl");
            Client client = dcf.createClient(url);  
            //消息发送时使用WebServiceRequestHeaderWrapper封装消息头
            client.getOutInterceptors().add(new WebServiceRequestHeaderWrapper());
            client.getInInterceptors().add(new WebserviceResponseHeaderParser());
//          client.getInInterceptors().add(new LoggingInInterceptor());
//          client.getOutInterceptors().add(new LoggingOutInterceptor());
            Object user= Thread.currentThread().getContextClassLoader().loadClass("com.ainoties.core.webservice.sample.User").newInstance();
            Method method = BeanUtils.findDeclaredMethod(user.getClass(), "setUsername", String.class);
            method.invoke(user, "xbz");
            Object[] res = client.invoke("hiUser", user);
            System.out.println(res[0]);
    }
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值