• 关于webservice框架CXF的总结


      首先,先说一下webservice的优点吧,websevice最大的优点就是可以跨平台跨语言远程调用,就是你在webservice平台上用java写了一个api发布了,其他象用C++,paython写的平台也能通过webservice调用你写的api,同样反过来也行的通。现在主流的webservice框架有Apache Axis1、Apache Axis2、Codehaus XFire、Apache CXF、sun JAX-WS(最简单、方便)等等,我接触到的就是Axis2和CXF,感觉CXF要比Axis2简洁,方便使用一点,https://www.cnblogs.com/ruiati/p/6640287.html  这位老哥对现在较为流行的webservice框架进行了对比,有兴趣的可以看看。好了接下来开始总结webservice知识和CXF框架。(因为楼主之前没有接触过webservice,所以会从最基本的开始)。

    1.webservice组成

      webservice由XML+XSD,SOAP和WSDL组成。

      1.1 xml+xsd

      webservice通过xml来发送数据,但是由于xml并不能明确定义数据格式,而不同平台之间的数据类型可能不一致,可能导致接受数据出现错误,所以,不同平台之间传输数据时需要统一数据规范,以统一的规范发送数据,再根据规范接受数据,这样就解决了传输数据类型问题。

      1.2 soap

      SOAP(simple object  access protocal)使用基于XML的数据结构超文本传输协议(HTTP)来传输数据。SOAP协议 = HTTP协议 + XML数据格式。

      1.3 wsdl

      wsdl:Web Service Description Language,即网络服务描述语言,用来告知使用或者准备使用的群体,该webservice接口的地址,需要传输什么内容,会返回什么内容,会调用那个方法等详细信息。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。 WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。

      1.4  SEI(WebService EndPoint Interface)

      SEI是web service的终端接口,就是WebService服务器端用来处理请求的接口。

    2.CXF框架

      这里我们只是写一下CXF发布服务和创建客户端的大概流程,不整合其他框架,只使用CXF。

      2.1创建服务端

      首先,创建一个maven项目(省的手动导包),jdk最好用1.7的,然后新建一个接口和其实现类,添加一个方法,重点是在准备发布的接口和其实现类上添加@webservice注解,标明这是要发布的接口。

       例如,我在接口中添加了两个方法,一个直接返回信息,一个做判断后返回。

      然后,我们需要发布已经写好的接口,首先我们要新建一个类,为方便理解命名为server。发布接口有两种方式,一种为Javax.xml.ws包下的Endpoint,是java自带的发布webservice的类,直接用该类的publish方法发布接口,发布的具体地址自己定义;另一种为org.apache.cxf.jaxws包下的JaxWsServerFactoryBean,是cxf的,可以设置要发布的地址,接口类,实现类,还可以添加输入输出拦截器,用拦截器可以实现接口的安全验证,添加白名单等操作。

      这样服务端基本就配置完了,对了,还要在maven中添加依赖,具体依赖如下。

           <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-core</artifactId>
                <version>3.1.5</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxws</artifactId>
                <version>3.1.5</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-transports-http-jetty</artifactId>
                <version>3.1.5</version>
            </dependency>

      

      然后我们启动tomcat,在浏览器上粘贴上我们定义的地址,并在后边添加?wsdl后缀,如果能够正常打开,看到service名称地址等,说明我们发布成功。

     

      

      2.2 创建客户端

      在我们创建客户端前,需要下载CXF框架,我们需要用到其中的wsdl2java工具,去CXF官网下载就可以,具体下载过程不再赘述,要注意的是下载完需要配置环境变量,将其添加到path中。

      现在我们新建一个maven项目,为客户端,我们创建客户端需要根据服务端发布的wsdl来生成,所以,首先我们需要启动之前的server端,然后在客户端项目中找到要生成文件的位置,在命令行中打开要生成文件的位置,用wsdl工具生成所需文件。

     

      

       若运行之后,如上图所示,表示成功生成了客户端代码,生成文件如下图所示。

      接下来,新建一个类,名为client,在其中new一个webservice客户端类,根据客户端类生成接口类,根据接口类来调用我们所需方法。

    public class Client {
        public static void main(String[] args) {
            HelloWorldServiceService helloworldServiceService =new HelloWorldServiceService();
    
            HelloWorldService helloworldService = helloworldServiceService.getHelloWorldServicePort();
    
            org.apache.cxf.endpoint.Client client = ClientProxy.getClient(helloworldService);
            client.getOutInterceptors().add(new AddHeaderInterceptor("lili","123"));//自定义输出拦截器
            client.getInInterceptors().add(new LoggingInInterceptor());//接收数据日志拦截器
            client.getOutInterceptors().add(new LoggingOutInterceptor());//发送数据日志拦截器
    
    //        List<String> nums = new ArrayList<String>();
    //        nums.add("一号");
    //        nums.add("二号");
    //        nums.add("三号");
    //        nums.add("六号");
    //        for (String num:nums
    //             ) {
    //            System.out.println(helloworldService.hi(num));
    //        }
    
            List<User> users = new ArrayList<User>();
            users.add(new User("丽丽","123"));
            users.add(new User("花花","123"));
            users.add(new User("菲菲","123"));
            for (User user:users
                 ) {
                Authority au = helloworldService.judgAuthority(user);
                System.out.println(au);
            }
        }
    }

      然后运行客户端main方法即可看到运行结果。

      这是client端的输出,因为我们这是简单测试,所以在server端方法的实现中直接写死了验证,用户名必须是“丽丽”或者“菲菲”密码都必须是123,而在client端我们第一个和第三个测试例子正确,第二个不正确,所以客户端的返回如下图。

       这是server端输出,server端我们让他输出他所接收到的内容。如下图。

       2.3 创建拦截器

      拦截器是webservice进行验证或过滤的重要方式,通过拦截器可以进行用户名密码验证(当然,你也可以在接口内部实现用户名密码验证,但是拦截器验证实在接受数据之前进行了拦截验证,更为安全严谨一些),ip验证等等,也是webservice保证接口安全的重要方式。

      CXF的拦截器主要有四种,客户端的输入拦截器,输出拦截器,服务器端的输入拦截器,输出拦截器,它们的总体流程是这样的,客户端输出拦截器——>服务端输入拦截器——>服务端输出拦截器——>客户端输入拦截器。

      首先我们可以先添加日志拦截器,给客户端服务端都加上输入输出拦截。主要方法为:getInInterceptor().add(要添加的拦截器),getOutInterceptor().add(要添加的拦截器)。

     

       

      然后启动服务端,运行客户端,会出现以下内容:

       上图是客户端的日志记录,可以详细看到客户端发送接收数据的详细情况,服务端同理,不再贴了。

      现在我们定义一个验证用户名密码的拦截器,分别在客户端和服务端添加输出拦截器和输入拦截器。

      首先在客户端天界一个输出拦截器,AddHeaderInterceptor,添加头信息的拦截器,用来给发送的数据的头部,添加用户名密码,方便服务端验证。注意,实际操作中,怎么验证,要服务端和客户端双方沟通,协商好通信验证的内容方式。

    public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    
        private String userName;
        private String password;
    
        public AddHeaderInterceptor(String userName, String password) {
            super(Phase.PREPARE_SEND);//这里的PREPARE_SEND表示在准备发送之前进行拦截
            this.userName=userName;
            this.password=password;
        }
    
        public void handleMessage(SoapMessage soapMessage) throws Fault {
            List<Header> headers = soapMessage.getHeaders();
            //因为发送的数据是xml格式的,所以此处是通过添加节点的方式添加用户名密码
            Document document = DOMUtils.createDocument();
            Element element = document.createElement("Auth");
            Element uElement = document.createElement("userName");//添加一个userName节点
            Element pElement = document.createElement("password");//添加一个password节点
            uElement.setTextContent(userName);//将用户名填写在节点中
            pElement.setTextContent(password);//将密码填写在节点中
            element.appendChild(uElement);
            element.appendChild(pElement);
            headers.add(new Header(new QName("auth"),element));
        }
    }

      

      客户端添加完成之后,同理,我们在服务端添加进行验证的拦截器。

    public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    
    
        public MyInterceptor() {
            super(Phase.PRE_INVOKE);//调用方法前调用自定义拦截器
        }
    
        public void handleMessage(SoapMessage soapMessage) throws Fault {
            List<Header> headers = soapMessage.getHeaders();
            if (headers==null||headers.size()==0){
                throw new Fault(new IllegalArgumentException("头部为空,请填写完整"));
            }
            
            //根据节点来读取数据
            Header header = headers.get(0);
            Element element = (Element) header.getObject();
            NodeList uList = element.getElementsByTagName("userName");
            NodeList pList = element.getElementsByTagName("password");
    
            if (uList.getLength()!=1){
                throw new Fault(new IllegalArgumentException("用户名格式不正确"));
            }
            if (pList.getLength()!=1){
                throw new Fault(new IllegalArgumentException("密码格式不正确"));
            }
            String userName = uList.item(0).getTextContent();
            String password = pList.item(0).getTextContent();
    
                if (!"lili".equals(userName)||!"123".equals(password)){
                    throw new Fault(new IllegalArgumentException("用户名密码不正确"));
                }
        }
    }

      

      为了方便,我们直接写死用户名密码,接下来我们测试一下。

      首先,测试一个错误的用户名密码,即用户名不为“lili”或者密码不为“123”,比如“feifei”,“123”

     

       

      从以上两图可以看到,客户端在接受完第一条返回值后就报了用户名密码错误的异常,服务端也是在接受完第一条数据后就报了异常,说明拦截器成功了。

      将客户端用户名密码改为正确的用户名密码后再次进行测试,结果正常。

     

    金无足赤,人无完人,若有文章什么问题欢迎各位批评指正,共同交流,共同进步。 另,人过留名,雁过留声,少侠觉得还行的话留下个赞吧!:)
  • 相关阅读:
    #writeup#pwnable unlink
    #pwnable#cmd2
    #writeup# 深交所CTF内训T2-上传漏洞
    #writeup# 深交所CTF内训T1-SQL注入
    HAProxy 基本翻译
    概况
    Day 2 @ RSA Conference Asia Pacific & Japan 2016
    Burp suite安装使用教程
    Windows server 2012 iis 网页HTTP 404.17
    SQL Server、MySQL、Oracle查询前n条记录
  • 原文地址:https://www.cnblogs.com/thePeaceOftheLord/p/11436556.html
Copyright © 2020-2023  润新知