Web Service学习-CXF开发Web Service的权限控制(二)
Web Service怎样进行权限控制?
解决思路:server端要求input消息总是携带实username。password信息,假设没实username和password信息。直接拒绝调用
解决方式:拦截器
为了让程序猿能訪问,并改动CXF框架所生成的SOAP消息,CXF提供了拦截器
CXF(Celtix +XFire)说明:
假设不用CXF等框架,SOAP消息的生成。解析都是由程序猿负责。不管是加入username。password信息还是提取username,password信息,都可由程序猿代码完毕。
假设使用CXF等框架,SOAP消息的生成,解析都是由CXF等框架来完毕。
总的来说,CXF对公布WebService进行了封装,简化了我们的操作。
拦截器:
服务端加入拦截器:
1,获取Endpoint的publish的方法返回值。
2,调用该对象的getInInterceptors,getOutInterceptors方法来获取In。Out拦截器列表,接下来就能够加入拦截器了
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,加入对应的CXF的jar包
2,调用ClientProxy的getClient方法,调用该方法以远程Web Service的代理为參数
3,调用Client对象的getInInterceptors。getOutInterceptors方法来获取In。Out拦截器列表,接下来就能够加入拦截器了
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()); } }
打印内容为:
自己定义拦截器
实现效果:当输入usernamepassword时。才干够调用我们的服务。
即我们须要在服务端加入输入拦截,在客户端加入输出拦截
自己定义拦截器,须要实现Interceptor接口,实际上,我们通常会继承AbstractPhaseInterceptor
服务端代码:
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就会负责检查username。password是否正确 ep.getInInterceptors().add(new AuthInterceptor()); //加入Out拦截器 // ep.getOutInterceptors().add(new LoggingOutInterceptor()); System.out.println("Web Service暴露成功"); } }
AuthInterceptor :
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携带了username,password信息 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("username的格式不对。")); } if(userPasses.getLength()!=1){ throw new Fault(new IllegalArgumentException("password的格式不对!")); } //得到第一个userId元素里的文本内容。以该内容作为username字 String userId=userIds.item(0).getTextContent(); String userPass=userPasses.item(0).getTextContent(); //实际项目中。应该去查询数据库,该usernamepassword是否被授权调用web service if(!userId.equals("hejingyuan") || !userPass.equals("hjy")){ throw new Fault(new IllegalArgumentException("usernamepassword不对!")); } } }
客户端代码:
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); //參数为输入的username。password 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:
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"); //此处创建的元素应该依照server那边的要求 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函数去訪问服务端提供的服务。
usernamepassword错误时:
usernamepassword正确时:
总结:
权限控制的实现方式为使用拦截器。对于拦截到的Soap消息进行改动。
SOAP消息:
根元素是Envolope
Header
默认情况下。Header元素不是强制出现的
Header元素由程序猿控制加入,主要用户携带一些额外的信息。比方username,password信息
Body
假设调用正确,Body元素的内容应该遵守WSDL所要求的格式
假设调用错误。Body元素的内容就是Fault子元素
相关文章
- 线程同步工具(六)控制并发阶段性任务的改变
- [Web 前端 ] 五大WEB主流浏览器及四大内核
- 云集,让 web app 像 native app 那样运行(雄起吧,Web 开发者)
- 【CTF WEB】ISCC 2016 web 2题记录
- delphi 完全控制Excel 文件
- 计算一/二元一次方程的类(用于动画控制)
- 【重点】Shell入门教程:流程控制(3)条件判断式的真假值
- ElasticSearch之 控制相关度原理讲解
- 《ASP.NET MVC4 WEB编程》学习笔记------Web API 续
- Web 开发中 20 个很有用的 CSS 库 - WEB开发者
- linux下通过acl配置灵活目录文件权限(可用于ftp,web服务器的用户权限控制)
- IAM:亚马逊访问权限控制
- linux下通过acl配置灵活目录文件权限(可用于ftp,web服务器的用户权限控制)
- SAP Spartacus split view控制同屏显示最大视图数的配置
- Atitit web 之道 艾龙著 Atitit web 之道 艾龙艾提拉著v2 saa.docx Atitit web开发之道 attilax著 Web应用 1. 第1章 Web编程基础知识 (
- Atitit.web三大编程模型 Web Page Web Forms 和 MVC
- Atitit.web三大编程模型 Web Page Web Forms 和 MVC
- Android修行手册-EditText属性以及光标和小键盘控制
- 设备和面向类的函数 基本的终端接口 termios termios 机构 取得前台进程组的 ID 设置前台进程组 ID 行控制函数 获得并设定状态 接口特性 波特率函数 基本的终端接口控制函数
- Nginx实践篇(2)- Nginx作为静态资源web服务 - 控制浏览器缓存、防盗链
- 005-优化web请求一-gzip压缩、http缓存控制和缓存校验[Pragma、Expires、Cache-Control、max-age、Last-Modified、用户刷新访问、避免过度304]
- 36.第六章 Shell脚本编程高级进阶 -- 流程控制(一)
- Linux,curl工具,测试web,数据流直接打印到控制平台
- 利用MCU实现制作一台蓝牙控制小车方法
- 从零实现Web框架Geo教程-分组控制-04
- Web自动化——介绍与安装以及第一个web自动化程序(一)