Web Service学习-CXF开发Web Service的权限控制(二)

    xiaoxiao2021-04-13  28

    Web Service如何进行权限控制?

     

    解决思路:服务器端要求input消息总是携带有用户名,密码信息,如果没有用户名和密码信息,直接拒绝调用

     

    解决方案:拦截器

     

    为了让程序员能访问,并修改CXF框架所生成的SOAP消息,CXF提供了拦截器

     

    CXF(Celtix +XFire)说明:

     

    如果不用CXF等框架,SOAP消息的生成,解析都是由程序员负责。无论是添加用户名,密码信息还是提取用户名,密码信息,都可由程序员代码完成。

    如果使用CXF等框架,SOAP消息的生成,解析都是由CXF等框架来完成。

     

    总的来说,CXF发布WebService进行了封装,简化了我们的操作。

     

    拦截器:

    服务端添加拦截器:

    1,获取Endpointpublish的方法返回值。

    2,调用该对象的getInInterceptors,getOutInterceptors方法来获取InOut拦截器列表,接下来就可以添加拦截器了

    [java]  view plain  copy  print ? package com.tgb.client;         import javax.xml.ws.Endpoint;      import org.apache.cxf.interceptor.LoggingInInterceptor;   import org.apache.cxf.interceptor.LoggingOutInterceptor;   import org.apache.cxf.jaxws.EndpointImpl;      import com.tgb.service.HelloWorld;   import com.tgb.service.impl.HelloWorldImpl;      public class ServerMain {          public static void main(String[] args){                      HelloWorld hw=new HelloWorldImpl();           //调用endpoint的publish方法,来发布web service   //      Endpoint.publish("http://192.168.24.215:8889/hjy",hw);           EndpointImpl ep=(EndpointImpl)Endpoint.publish("http://192.168.24.215:8899/hjy",hw);                      //添加In拦截器           ep.getInInterceptors().add(new LoggingInInterceptor());           //添加Out拦截器           ep.getOutInterceptors().add(new LoggingOutInterceptor());                      System.out.println("Web Service暴露成功");       }   }  

    输出内容:

    客户端添加拦截器:

     

    1,添加相应的CXFjar

    2,调用ClientProxy的getClient方法,调用该方法以远程Web Service的代理为参数

    3,调用Client对象的getInInterceptors,getOutInterceptors方法来获取InOut拦截器列表,接下来就可以添加拦截器了

    [java]  view plain  copy  print ? package hjy;      import java.util.List;      import org.apache.cxf.endpoint.Client;   import org.apache.cxf.frontend.ClientProxy;   import org.apache.cxf.interceptor.LoggingInInterceptor;   import org.apache.cxf.interceptor.LoggingOutInterceptor;      import com.tgb.service.Cat;   import com.tgb.service.HelloWorld;   import com.tgb.service.User;   import com.tgb.service.impl.HelloWorldImpl;      public class ClientMain {          public static void main(String[] args){           HelloWorldImpl factory=new HelloWorldImpl();           //此处返回的只是远程Web Service的代理           HelloWorld hw=factory.getHelloWorldImplPort();                      Client client=ClientProxy.getClient(hw);           client.getInInterceptors().add(new LoggingInInterceptor());           client.getOutInterceptors().add(new LoggingOutInterceptor());                      System.out.println(hw.sayHi("hejingyuan"));                      System.out.println("--------------------------");                      User user=new User();           user.setId(20);           user.setName("孙悟空");           user.setPass("111");           user.setAddress("花果山");                      List<Cat> cats=hw.getCatsByUser(user);           for(Cat cat:cats){               System.out.println(cat.getName());           }                      System.out.println("--------------------------");                      System.out.println(hw.getAllCats().getEntry().get(0).getKey());           System.out.println(hw.getAllCats().getEntry().get(0).getValue().getName());                                }   }    

    打印内容为:

    自定义拦截器

     

    实现效果:当输入用户名密码时,才可以调用我们的服务。即我们需要在服务端添加输入拦截,在客户端添加输出拦截

    自定义拦截器,需要实现Interceptor接口,实际上,我们一般会继承AbstractPhaseInterceptor

     

    服务端代码:

    [java]  view plain  copy  print ? package com.tgb.client;         import javax.xml.ws.Endpoint;      import org.apache.cxf.interceptor.LoggingInInterceptor;   import org.apache.cxf.interceptor.LoggingOutInterceptor;   import org.apache.cxf.jaxws.EndpointImpl;      import com.tgb.auth.AuthInterceptor;   import com.tgb.service.HelloWorld;   import com.tgb.service.impl.HelloWorldImpl;      public class ServerMain {          public static void main(String[] args){                      HelloWorld hw=new HelloWorldImpl();           //调用endpoint的publish方法,来发布web service   //      Endpoint.publish("http://192.168.24.215:8889/hjy",hw);           EndpointImpl ep=(EndpointImpl)Endpoint.publish("http://192.168.24.215:8891/hjy",hw);                      //添加In拦截器,该AuthInterceptor就会负责检查用户名,密码是否正确           ep.getInInterceptors().add(new AuthInterceptor());           //添加Out拦截器   //      ep.getOutInterceptors().add(new LoggingOutInterceptor());                      System.out.println("Web Service暴露成功");       }   }  

    AuthInterceptor :

    [java]  view plain  copy  print ? package com.tgb.auth;      import java.util.List;      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.w3c.dom.Element;   import org.w3c.dom.NodeList;         //通过PhaseInterceptor,可以指定拦截器在哪个阶段起作用   public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>{          //由于AbstractPhaseInterceptor无无参数构造器,使用继承的方式,需要显示调用父类有参数的构造器       public AuthInterceptor(){           //super表示显示调用父类有参数的构造器           //显示调用父类构造器之后,程序将不会隐式调用父类无参数的构造器           super(Phase.PRE_INVOKE);//该拦截器将会调用之前拦截SOAP消息       }       //实现自己的拦截器时,需要实现handleMessage方法。       //handleMessage方法中的形参就是被拦截到的Soap消息       //一旦程序获取了SOAP消息,剩下的事情就可以解析SOAP消息或修改SOAP消息       @Override       public void handleMessage(SoapMessage msg) throws Fault {                      System.out.println("-------"+msg);           //从这里可以看出,我们已经拦截到了SOAP消息                      //得到SOAP消息所有Header           List<Header> headers=msg.getHeaders();                      //如果没有Header           if(headers==null||headers.size()<1){               throw new Fault(new IllegalArgumentException("根本没有Header,不能调用"));                                  }                      //假如要求第一个Header携带了用户名,密码信息           Header firstHeader=headers.get(0);           Element ele=(Element)firstHeader.getObject();                      NodeList userIds=ele.getElementsByTagName("userId");           NodeList userPasses=ele.getElementsByTagName("userPass");                      if(userIds.getLength()!=1){               throw new Fault(new IllegalArgumentException("用户名的格式不正确!"));           }           if(userPasses.getLength()!=1){               throw new Fault(new IllegalArgumentException("密码的格式不正确!"));           }                      //得到第一个userId元素里的文本内容,以该内容作为用户名字           String userId=userIds.item(0).getTextContent();           String userPass=userPasses.item(0).getTextContent();           //实际项目中,应该去查询数据库,该用户名密码是否被授权调用web service           if(!userId.equals("hejingyuan") || !userPass.equals("hjy")){               throw new Fault(new IllegalArgumentException("用户名密码不正确!"));           }       }      }  

    客户端代码:

    [java]  view plain  copy  print ? package hjy;      import java.util.List;      import org.apache.cxf.endpoint.Client;   import org.apache.cxf.frontend.ClientProxy;      import com.tgb.auth.AddHeaderInterceptor;   import com.tgb.service.Cat;   import com.tgb.service.HelloWorld;   import com.tgb.service.User;   import com.tgb.service.impl.HelloWorldImpl;      public class ClientMain {          public static void main(String[] args){           HelloWorldImpl factory=new HelloWorldImpl();           //此处返回的只是远程Web Service的代理           HelloWorld hw=factory.getHelloWorldImplPort();                      Client client=ClientProxy.getClient(hw);           //参数为输入的用户名,密码           client.getOutInterceptors().add(new AddHeaderInterceptor("hejingyuan","hjy"));                      System.out.println(hw.sayHi("hejingyuan"));                      System.out.println("--------------------------");                      User user=new User();           user.setId(20);           user.setName("孙悟空");           user.setPass("111");           user.setAddress("花果山");                      List<Cat> cats=hw.getCatsByUser(user);           for(Cat cat:cats){               System.out.println(cat.getName());           }                      System.out.println("--------------------------");                      System.out.println(hw.getAllCats().getEntry().get(0).getKey());           System.out.println(hw.getAllCats().getEntry().get(0).getValue().getName());                     }   }  

    AddHeaderInterceptor:

    [java]  view plain  copy  print ? package com.tgb.auth;      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.helpers.DOMUtils;   import org.apache.cxf.interceptor.Fault;   import org.apache.cxf.phase.AbstractPhaseInterceptor;   import org.apache.cxf.phase.Phase;   import org.w3c.dom.Document;   import org.w3c.dom.Element;         public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{          private String userId;       private String userPass;              public AddHeaderInterceptor(String userId,String userPass){           super(Phase.PREPARE_SEND);//在准备发送SOAP消息时启用该拦截器           this.userId=userId;           this.userPass=userPass;       }       @Override       public void handleMessage(SoapMessage msg) throws Fault {           List<Header> headers=msg.getHeaders();           //创建Document对象           Document doc=DOMUtils.createDocument();           Element ele=doc.createElement("authHeader");                      //此处创建的元素应该按照服务器那边的要求           Element idEle=doc.createElement("userId");           idEle.setTextContent(userId);           Element passEle=doc.createElement("userPass");           passEle.setTextContent(userPass);                      ele.appendChild(idEle);           ele.appendChild(passEle);                      /**           * 上面代码生成了一个如下XML文档片段           * <authHeader>           *      <userId>hejingyuan</userId>           *      <userPass>hjy</userPass>           * </authHeader>           */           //把ele元素包装成Header,并添加到SOAP消息的Header列表中           headers.add(new Header(new QName("hejingyuan"),ele));       }      }  

    启动服务端的ServerMain的main函数,将服务发布,然后启动客户端ClientMain的main函数去访问服务端提供的服务。

    用户名密码错误时:

    用户名密码正确时:

    总结:

     

    权限控制的实现方式为使用拦截器,对于拦截到的Soap消息进行修改。

    SOAP消息:

    根元素是Envolope

    Header

    默认情况下,Header元素不是强制出现的

    Header元素由程序员控制添加,主要用户携带一些额外的信息,比如用户名,密码信息

    Body

    如果调用正确,Body元素的内容应该遵守WSDL所要求的格式

    如果调用错误,Body元素的内容就是Fault子元素

    源码下载

    转载请注明原文地址: https://ju.6miu.com/read-668643.html

    最新回复(0)