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

来源:互联网 发布:mac 删除文件 编辑:程序博客网 时间:2024/05/17 08:01

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?
  1. package com.tgb.client;  
  2.   
  3.   
  4. import javax.xml.ws.Endpoint;  
  5.   
  6. import org.apache.cxf.interceptor.LoggingInInterceptor;  
  7. import org.apache.cxf.interceptor.LoggingOutInterceptor;  
  8. import org.apache.cxf.jaxws.EndpointImpl;  
  9.   
  10. import com.tgb.service.HelloWorld;  
  11. import com.tgb.service.impl.HelloWorldImpl;  
  12.   
  13. public class ServerMain {  
  14.   
  15.     public static void main(String[] args){  
  16.           
  17.         HelloWorld hw=new HelloWorldImpl();  
  18.         //调用endpoint的publish方法,来发布web service  
  19. //      Endpoint.publish("http://192.168.24.215:8889/hjy",hw);  
  20.         EndpointImpl ep=(EndpointImpl)Endpoint.publish("http://192.168.24.215:8899/hjy",hw);  
  21.           
  22.         //添加In拦截器  
  23.         ep.getInInterceptors().add(new LoggingInInterceptor());  
  24.         //添加Out拦截器  
  25.         ep.getOutInterceptors().add(new LoggingOutInterceptor());  
  26.           
  27.         System.out.println("Web Service暴露成功");  
  28.     }  
  29. }  

输出内容:




客户端添加拦截器:

 

1,添加相应的CXFjar

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

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


[java] view plain copy
 print?
  1. package hjy;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.apache.cxf.endpoint.Client;  
  6. import org.apache.cxf.frontend.ClientProxy;  
  7. import org.apache.cxf.interceptor.LoggingInInterceptor;  
  8. import org.apache.cxf.interceptor.LoggingOutInterceptor;  
  9.   
  10. import com.tgb.service.Cat;  
  11. import com.tgb.service.HelloWorld;  
  12. import com.tgb.service.User;  
  13. import com.tgb.service.impl.HelloWorldImpl;  
  14.   
  15. public class ClientMain {  
  16.   
  17.     public static void main(String[] args){  
  18.         HelloWorldImpl factory=new HelloWorldImpl();  
  19.         //此处返回的只是远程Web Service的代理  
  20.         HelloWorld hw=factory.getHelloWorldImplPort();  
  21.           
  22.         Client client=ClientProxy.getClient(hw);  
  23.         client.getInInterceptors().add(new LoggingInInterceptor());  
  24.         client.getOutInterceptors().add(new LoggingOutInterceptor());  
  25.           
  26.         System.out.println(hw.sayHi("hejingyuan"));  
  27.           
  28.         System.out.println("--------------------------");  
  29.           
  30.         User user=new User();  
  31.         user.setId(20);  
  32.         user.setName("孙悟空");  
  33.         user.setPass("111");  
  34.         user.setAddress("花果山");  
  35.           
  36.         List<Cat> cats=hw.getCatsByUser(user);  
  37.         for(Cat cat:cats){  
  38.             System.out.println(cat.getName());  
  39.         }  
  40.           
  41.         System.out.println("--------------------------");  
  42.           
  43.         System.out.println(hw.getAllCats().getEntry().get(0).getKey());  
  44.         System.out.println(hw.getAllCats().getEntry().get(0).getValue().getName());  
  45.           
  46.           
  47.   
  48.     }  
  49. }  
 

打印内容为:




自定义拦截器

 

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

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

 

服务端代码:


[java] view plain copy
 print?
  1. package com.tgb.client;  
  2.   
  3.   
  4. import javax.xml.ws.Endpoint;  
  5.   
  6. import org.apache.cxf.interceptor.LoggingInInterceptor;  
  7. import org.apache.cxf.interceptor.LoggingOutInterceptor;  
  8. import org.apache.cxf.jaxws.EndpointImpl;  
  9.   
  10. import com.tgb.auth.AuthInterceptor;  
  11. import com.tgb.service.HelloWorld;  
  12. import com.tgb.service.impl.HelloWorldImpl;  
  13.   
  14. public class ServerMain {  
  15.   
  16.     public static void main(String[] args){  
  17.           
  18.         HelloWorld hw=new HelloWorldImpl();  
  19.         //调用endpoint的publish方法,来发布web service  
  20. //      Endpoint.publish("http://192.168.24.215:8889/hjy",hw);  
  21.         EndpointImpl ep=(EndpointImpl)Endpoint.publish("http://192.168.24.215:8891/hjy",hw);  
  22.           
  23.         //添加In拦截器,该AuthInterceptor就会负责检查用户名,密码是否正确  
  24.         ep.getInInterceptors().add(new AuthInterceptor());  
  25.         //添加Out拦截器  
  26. //      ep.getOutInterceptors().add(new LoggingOutInterceptor());  
  27.           
  28.         System.out.println("Web Service暴露成功");  
  29.     }  
  30. }  

AuthInterceptor :


[java] view plain copy
 print?
  1. package com.tgb.auth;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.apache.cxf.binding.soap.SoapMessage;  
  6. import org.apache.cxf.headers.Header;  
  7. import org.apache.cxf.interceptor.Fault;  
  8. import org.apache.cxf.phase.AbstractPhaseInterceptor;  
  9. import org.apache.cxf.phase.Phase;  
  10. import org.w3c.dom.Element;  
  11. import org.w3c.dom.NodeList;  
  12.   
  13.   
  14. //通过PhaseInterceptor,可以指定拦截器在哪个阶段起作用  
  15. public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>{  
  16.   
  17.     //由于AbstractPhaseInterceptor无无参数构造器,使用继承的方式,需要显示调用父类有参数的构造器  
  18.     public AuthInterceptor(){  
  19.         //super表示显示调用父类有参数的构造器  
  20.         //显示调用父类构造器之后,程序将不会隐式调用父类无参数的构造器  
  21.         super(Phase.PRE_INVOKE);//该拦截器将会调用之前拦截SOAP消息  
  22.     }  
  23.     //实现自己的拦截器时,需要实现handleMessage方法。  
  24.     //handleMessage方法中的形参就是被拦截到的Soap消息  
  25.     //一旦程序获取了SOAP消息,剩下的事情就可以解析SOAP消息或修改SOAP消息  
  26.     @Override  
  27.     public void handleMessage(SoapMessage msg) throws Fault {  
  28.           
  29.         System.out.println("-------"+msg);  
  30.         //从这里可以看出,我们已经拦截到了SOAP消息  
  31.           
  32.         //得到SOAP消息所有Header  
  33.         List<Header> headers=msg.getHeaders();  
  34.           
  35.         //如果没有Header  
  36.         if(headers==null||headers.size()<1){  
  37.             throw new Fault(new IllegalArgumentException("根本没有Header,不能调用"));                         
  38.         }  
  39.           
  40.         //假如要求第一个Header携带了用户名,密码信息  
  41.         Header firstHeader=headers.get(0);  
  42.         Element ele=(Element)firstHeader.getObject();  
  43.           
  44.         NodeList userIds=ele.getElementsByTagName("userId");  
  45.         NodeList userPasses=ele.getElementsByTagName("userPass");  
  46.           
  47.         if(userIds.getLength()!=1){  
  48.             throw new Fault(new IllegalArgumentException("用户名的格式不正确!"));  
  49.         }  
  50.         if(userPasses.getLength()!=1){  
  51.             throw new Fault(new IllegalArgumentException("密码的格式不正确!"));  
  52.         }  
  53.           
  54.         //得到第一个userId元素里的文本内容,以该内容作为用户名字  
  55.         String userId=userIds.item(0).getTextContent();  
  56.         String userPass=userPasses.item(0).getTextContent();  
  57.         //实际项目中,应该去查询数据库,该用户名密码是否被授权调用web service  
  58.         if(!userId.equals("hejingyuan") || !userPass.equals("hjy")){  
  59.             throw new Fault(new IllegalArgumentException("用户名密码不正确!"));  
  60.         }  
  61.     }  
  62.   
  63. }  

客户端代码:


[java] view plain copy
 print?
  1. package hjy;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.apache.cxf.endpoint.Client;  
  6. import org.apache.cxf.frontend.ClientProxy;  
  7.   
  8. import com.tgb.auth.AddHeaderInterceptor;  
  9. import com.tgb.service.Cat;  
  10. import com.tgb.service.HelloWorld;  
  11. import com.tgb.service.User;  
  12. import com.tgb.service.impl.HelloWorldImpl;  
  13.   
  14. public class ClientMain {  
  15.   
  16.     public static void main(String[] args){  
  17.         HelloWorldImpl factory=new HelloWorldImpl();  
  18.         //此处返回的只是远程Web Service的代理  
  19.         HelloWorld hw=factory.getHelloWorldImplPort();  
  20.           
  21.         Client client=ClientProxy.getClient(hw);  
  22.         //参数为输入的用户名,密码  
  23.         client.getOutInterceptors().add(new AddHeaderInterceptor("hejingyuan","hjy"));  
  24.           
  25.         System.out.println(hw.sayHi("hejingyuan"));  
  26.           
  27.         System.out.println("--------------------------");  
  28.           
  29.         User user=new User();  
  30.         user.setId(20);  
  31.         user.setName("孙悟空");  
  32.         user.setPass("111");  
  33.         user.setAddress("花果山");  
  34.           
  35.         List<Cat> cats=hw.getCatsByUser(user);  
  36.         for(Cat cat:cats){  
  37.             System.out.println(cat.getName());  
  38.         }  
  39.           
  40.         System.out.println("--------------------------");  
  41.           
  42.         System.out.println(hw.getAllCats().getEntry().get(0).getKey());  
  43.         System.out.println(hw.getAllCats().getEntry().get(0).getValue().getName());  
  44.           
  45.   
  46.     }  
  47. }  

AddHeaderInterceptor:


[java] view plain copy
 print?
  1. package com.tgb.auth;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.xml.namespace.QName;  
  6.   
  7. import org.apache.cxf.binding.soap.SoapMessage;  
  8. import org.apache.cxf.headers.Header;  
  9. import org.apache.cxf.helpers.DOMUtils;  
  10. import org.apache.cxf.interceptor.Fault;  
  11. import org.apache.cxf.phase.AbstractPhaseInterceptor;  
  12. import org.apache.cxf.phase.Phase;  
  13. import org.w3c.dom.Document;  
  14. import org.w3c.dom.Element;  
  15.   
  16.   
  17. public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{  
  18.   
  19.     private String userId;  
  20.     private String userPass;  
  21.       
  22.     public AddHeaderInterceptor(String userId,String userPass){  
  23.         super(Phase.PREPARE_SEND);//在准备发送SOAP消息时启用该拦截器  
  24.         this.userId=userId;  
  25.         this.userPass=userPass;  
  26.     }  
  27.     @Override  
  28.     public void handleMessage(SoapMessage msg) throws Fault {  
  29.         List<Header> headers=msg.getHeaders();  
  30.         //创建Document对象  
  31.         Document doc=DOMUtils.createDocument();  
  32.         Element ele=doc.createElement("authHeader");  
  33.           
  34.         //此处创建的元素应该按照服务器那边的要求  
  35.         Element idEle=doc.createElement("userId");  
  36.         idEle.setTextContent(userId);  
  37.         Element passEle=doc.createElement("userPass");  
  38.         passEle.setTextContent(userPass);  
  39.           
  40.         ele.appendChild(idEle);  
  41.         ele.appendChild(passEle);  
  42.           
  43.         /** 
  44.          * 上面代码生成了一个如下XML文档片段 
  45.          * <authHeader> 
  46.          *      <userId>hejingyuan</userId> 
  47.          *      <userPass>hjy</userPass> 
  48.          * </authHeader> 
  49.          */  
  50.         //把ele元素包装成Header,并添加到SOAP消息的Header列表中  
  51.         headers.add(new Header(new QName("hejingyuan"),ele));  
  52.     }  
  53.   
  54. }  


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

用户名密码错误时:




用户名密码正确时:




总结:

 

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

SOAP消息:

根元素是Envolope

Header

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

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

Body

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

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



源码下载

0 0
原创粉丝点击