WebService如果涉及到安全保密或者使用权限的时候,WS-Security通常是最优选择。WS-Security (Web服务安全)
包含了关于如何在WebService消息上保证完整性和机密性的规约,如何将签名和加密头加入SOAP消息。
不过WS-Security也有一些性能上的损耗,在信息保密要求不是很高的情况下,可以通过在SOAPHeader中添加简单的校验信息实现。
具体思路是客户端调用需要认证的服务时,在SOAPHeader中添加授权信息(如用户名、密码或者序列号等)。
服务端收到请求,在SOAPHeader中校验授权信息,校验通过则执行请求,校验不通过则返回错误提示。

客户端发起请求在SOAPHeader中添加的授权数据格式如下

  1. <auth xmlns="http://schemas.xmlsoap.org/soap/actor/next">
  2. <username>admin</username>
  3. <password>admin</password>
  4. </auth>

服务端

服务端授权校验 Handler

  1. import java.util.Iterator;
  2. import java.util.Set;
  3.  
  4. import javax.xml.namespace.QName;
  5. import javax.xml.soap.SOAPBody;
  6. import javax.xml.soap.SOAPConstants;
  7. import javax.xml.soap.SOAPElement;
  8. import javax.xml.soap.SOAPEnvelope;
  9. import javax.xml.soap.SOAPException;
  10. import javax.xml.soap.SOAPFault;
  11. import javax.xml.soap.SOAPHeader;
  12. import javax.xml.soap.SOAPMessage;
  13. import javax.xml.ws.handler.MessageContext;
  14. import javax.xml.ws.handler.soap.SOAPHandler;
  15. import javax.xml.ws.handler.soap.SOAPMessageContext;
  16.  
  17. import org.apache.cxf.interceptor.Fault;
  18. import org.w3c.dom.NodeList;
  19.  
  20. /**
  21. *
  22. * @author
  23. */
  24. public class JaxServerAuthValidateHeader implements SOAPHandler<SOAPMessageContext> {
  25.  
  26. @Override
  27. public void close(MessageContext context) {
  28. }
  29.  
  30. @Override
  31. public boolean handleFault(SOAPMessageContext context) {
  32. return true;
  33. }
  34.  
  35. @Override
  36. public boolean handleMessage(SOAPMessageContext context) {
  37.  
  38. // 判断消息是输入还是输出
  39. boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
  40. SOAPMessage soapMessage = context.getMessage();
  41.  
  42. if (!isRequest) {
  43.  
  44. SOAPHeader soapHeader = null;
  45.  
  46. try {
  47. SOAPEnvelope soapEnv = soapMessage.getSOAPPart().getEnvelope();
  48. soapHeader = soapEnv.getHeader();
  49. } catch (SOAPException e) {
  50. throw new Fault(new Exception("服务器异常!"));
  51. }
  52.  
  53. if (soapHeader == null) {
  54. validateFail(soapMessage, "无 Soap Header 头信息!");
  55. return false;
  56. }
  57.  
  58. // add an node named "auth"
  59. QName qname = new QName(SOAPConstants.URI_SOAP_ACTOR_NEXT, "auth");
  60. Iterator<?> iterator = soapHeader.getChildElements(qname);
  61. SOAPElement auth = null;
  62. if (iterator.hasNext()) {
  63. // 获取auth
  64. auth = (SOAPElement) iterator.next();
  65. }
  66.  
  67. // 如果授权信息元素不存在,提示错误
  68. if (auth == null) {
  69. validateFail(soapMessage, "无授权信息!");
  70. return false;
  71. }
  72.  
  73. NodeList nameList = auth.getElementsByTagName("username");
  74. NodeList pwdList = auth.getElementsByTagName("password");
  75. if (nameList == null || nameList.getLength() <= 0 || pwdList == null || pwdList.getLength() <= 0) {
  76. validateFail(soapMessage, "授权信息格式错误!");
  77. return false;
  78. }
  79.  
  80. String username = nameList.item(0).getTextContent();
  81. String password = pwdList.item(0).getTextContent();
  82. if (!"admin".equals(username) || !"admin".equals(password)) {
  83. validateFail(soapMessage, "授权信息格式错误!");
  84. return false;
  85. }
  86.  
  87. }
  88.  
  89. System.out.println(isRequest ? "服务端响应:" : "服务端接收:");
  90. System.out.println("\r\n");
  91.  
  92. return true;
  93.  
  94. }
  95.  
  96. @Override
  97. public Set<QName> getHeaders() {
  98. return null;
  99. }
  100.  
  101. /**
  102. * 授权校验失败,在SOAPBody中添加SOAPFault
  103. *
  104. * @param message
  105. */
  106. private void validateFail(SOAPMessage soapMessage, String faultString) {
  107. try {
  108.  
  109. SOAPEnvelope envelop = soapMessage.getSOAPPart().getEnvelope();
  110.  
  111. envelop.getHeader().detachNode();
  112. envelop.addHeader();
  113.  
  114. envelop.getBody().detachNode();
  115. SOAPBody body = envelop.addBody();
  116.  
  117. SOAPFault fault = body.getFault();
  118.  
  119. if (fault == null) {
  120. fault = body.addFault();
  121. }
  122.  
  123. fault.setFaultString(faultString);
  124.  
  125. soapMessage.saveChanges();
  126.  
  127. } catch (SOAPException e) {
  128. e.printStackTrace();
  129. }
  130. }
  131.  
  132. }

服务端Handler配置文件handler-chain.xml 

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  4. <javaee:handler-chain>
  5. <javaee:handler>
  6. <javaee:handler-class>com.server.handler.JaxServerAuthValidateHeader</javaee:handler-class>
  7. </javaee:handler>
  8. </javaee:handler-chain>
  9. </javaee:handler-chains>

服务端的Service中添加Handler配置文件

  1. import javax.jws.WebMethod;
  2. import javax.jws.WebParam;
  3. import javax.jws.WebResult;
  4. import javax.jws.WebService;
  5. import javax.xml.bind.annotation.XmlSeeAlso;
  6. import javax.xml.ws.RequestWrapper;
  7. import javax.xml.ws.ResponseWrapper;
  8.  
  9. /**
  10. * This class was generated by Apache CXF 3.2.1
  11. * 2017-12-01T14:12:00.085+08:00
  12. * Generated source version: 3.2.1
  13. *
  14. */
  15. @WebService(targetNamespace = "http://tempuri.org/", name = "AExampleDemoWebService")
  16. @HandlerChain(file="handler-chain.xml")
  17. public interface AExampleDemoWebService {
  18.  
  19. @WebMethod
  20. @WebResult(name = "single", targetNamespace = "")
  21. public java.lang.String querySingle(
  22. @WebParam(name = "single", targetNamespace = "http://tempuri.org/")
  23. java.lang.String single
  24. );
  25.  
  26. }

服务端的Service 实现类

  1. import java.util.ArrayList;
  2. import java.util.List;
  3.  
  4. import cn.evun.iwm.receive.soap.service.AExampleDemoWebService;
  5. import cn.evun.iwm.receive.soap.struc.sample.InputParam;
  6. import cn.evun.iwm.receive.soap.struc.sample.OutputParam;
  7.  
  8. @javax.jws.WebService(serviceName = "aexampleDemoWebService", portName = "Sample",
  9. targetNamespace = "http://tempuri.org/", endpointInterface = "cn.soap.service.AExampleDemoWebService")
  10. public class AExampleDemoWebServiceImpl implements AExampleDemoWebService {
  11.  
  12. @Override
  13. public String querySingle(String input) {
  14. return "success";
  15. }
  16.  
  17. }

客户端

客户端添加授权Handler

  1. import java.io.IOException;
  2. import java.util.Set;
  3.  
  4. import javax.xml.namespace.QName;
  5. import javax.xml.soap.SOAPConstants;
  6. import javax.xml.soap.SOAPElement;
  7. import javax.xml.soap.SOAPException;
  8. import javax.xml.soap.SOAPHeader;
  9. import javax.xml.soap.SOAPMessage;
  10. import javax.xml.ws.handler.MessageContext;
  11. import javax.xml.ws.handler.soap.SOAPHandler;
  12. import javax.xml.ws.handler.soap.SOAPMessageContext;
  13.  
  14. public class JaxWsClientHandler implements SOAPHandler<SOAPMessageContext> {
  15.  
  16. @Override
  17. public boolean handleMessage(SOAPMessageContext context) {
  18.  
  19. // 判断消息是请求还是响应
  20. Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
  21. SOAPMessage soapMessage = context.getMessage();
  22.  
  23. if (isRequest) {
  24.  
  25. try {
  26.  
  27. SOAPHeader soapHeader = soapMessage.getSOAPHeader();
  28. if (soapHeader == null) {
  29. soapHeader = soapMessage.getSOAPPart().getEnvelope().addHeader();
  30. }
  31.  
  32. // add an node named "auth"
  33. QName qname = new QName(SOAPConstants.URI_SOAP_ACTOR_NEXT, "auth");
  34. SOAPElement auth = soapHeader.addChildElement(qname);
  35.  
  36. SOAPElement name = auth.addChildElement("username");
  37. name.addTextNode("admin");
  38.  
  39. SOAPElement password = auth.addChildElement("password");
  40. password.addTextNode("admin");
  41.  
  42. soapMessage.saveChanges();
  43.  
  44. // tracking
  45. soapMessage.writeTo(System.out);
  46.  
  47. } catch (SOAPException e) {
  48. System.err.println(e);
  49. } catch (IOException e) {
  50. System.err.println(e);
  51. }
  52.  
  53. }
  54.  
  55. return true;
  56.  
  57. }
  58.  
  59. @Override
  60. public boolean handleFault(SOAPMessageContext context) {
  61. return false;
  62. }
  63.  
  64. @Override
  65. public void close(MessageContext context) {
  66.  
  67. }
  68.  
  69. @Override
  70. public Set<QName> getHeaders() {
  71. return null;
  72. }
  73.  
  74. }

客户端Handler配置文件handler-chain.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  4. <javaee:handler-chain>
  5. <javaee:handler>
  6. <javaee:handler-class>com.client.handler.JaxWsClientHandler</javaee:handler-class>
  7. </javaee:handler>
  8. </javaee:handler-chain>
  9. </javaee:handler-chains>

客户端的Service中添加Handler配置文件

  1. import java.net.MalformedURLException;
  2. import java.net.URL;
  3. import javax.xml.namespace.QName;
  4. import javax.xml.ws.WebEndpoint;
  5. import javax.xml.ws.WebServiceClient;
  6. import javax.xml.ws.WebServiceFeature;
  7.  
  8. import javax.xml.ws.Service;
  9.  
  10. /**
  11. * This class was generated by Apache CXF 3.2.1
  12. * 2017-12-01T14:12:00.117+08:00
  13. * Generated source version: 3.2.1
  14. *
  15. */
  16. @WebServiceClient(name = "aexampleDemoWebService",
  17. wsdlLocation = "http://localhost:8090/service/Sample?wsdl",
  18. targetNamespace = "http://tempuri.org/")
  19. @HandlerChain(file="handler-chain.xml")
  20. public class AexampleDemoWebServiceSoap extends Service {
  21.  
  22. public final static URL WSDL_LOCATION;
  23.  
  24. public final static QName SERVICE = new QName("http://tempuri.org/", "aexampleDemoWebService");
  25. public final static QName Sample = new QName("http://tempuri.org/", "Sample");
  26. static {
  27. URL url = null;
  28. try {
  29. url = new URL("http://localhost:8090/service/Sample?wsdl");
  30. } catch (MalformedURLException e) {
  31. java.util.logging.Logger.getLogger(AexampleDemoWebServiceSoap.class.getName())
  32. .log(java.util.logging.Level.INFO,
  33. "Can not initialize the default wsdl from {0}", "http://localhost:8090/service/Sample?wsdl");
  34. }
  35. WSDL_LOCATION = url;
  36. }
  37.  
  38. public AexampleDemoWebServiceSoap(URL wsdlLocation) {
  39. super(wsdlLocation, SERVICE);
  40. }
  41.  
  42. public AexampleDemoWebServiceSoap(URL wsdlLocation, QName serviceName) {
  43. super(wsdlLocation, serviceName);
  44. }
  45.  
  46. public AexampleDemoWebServiceSoap() {
  47. super(WSDL_LOCATION, SERVICE);
  48. }
  49.  
  50. public AexampleDemoWebServiceSoap(WebServiceFeature ... features) {
  51. super(WSDL_LOCATION, SERVICE, features);
  52. }
  53.  
  54. public AexampleDemoWebServiceSoap(URL wsdlLocation, WebServiceFeature ... features) {
  55. super(wsdlLocation, SERVICE, features);
  56. }
  57.  
  58. public AexampleDemoWebServiceSoap(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) {
  59. super(wsdlLocation, serviceName, features);
  60. }
  61.  
  62. /**
  63. *
  64. * @return
  65. * returns AExampleDemoWebService
  66. */
  67. @WebEndpoint(name = "Sample")
  68. public AExampleDemoWebService getSample() {
  69. return super.getPort(Sample, AExampleDemoWebService.class);
  70. }
  71.  
  72. /**
  73. *
  74. * @param features
  75. * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.
       *   Supported features not in the <code>features</code> parameter will have their default values.
  76. * @return
  77. * returns AExampleDemoWebService
  78. */
  79. @WebEndpoint(name = "Sample")
  80. public AExampleDemoWebService getSample(WebServiceFeature... features) {
  81. return super.getPort(Sample, AExampleDemoWebService.class, features);
  82. }
  83.  
  84. }

客户端发起请求

  1. QName SERVICE_NAME = new QName("http://tempuri.org/", "aexampleDemoWebService");
  2. URL url = new URL("http://localhost:8090/service/Sample?wsdl");
  3. AexampleDemoWebServiceSoap ss = new AexampleDemoWebServiceSoap(wsdlURL, SERVICE_NAME);
  4. AExampleDemoWebService port = ss.getSample();
  5. port.querySingle("1111");

@HandlerChain 注解 替代方式

  客户端  通过 HandlerReolver 代替 @HandlerChain 注解 导入 Handler 配置文件

  handler-chain配置文件对所有的请求都添加授权验证信息,有些时候不是所有的请求都需要添加授权验证,HandlerResolver提供了在编程时添加Handler的方法,可以用HandlerResolver给需要授权的接口添加Handler。

  1. QName SERVICE_NAME = new QName("http://tempuri.org/", "aexampleDemoWebService");
  2. URL url = new URL("http://localhost:8090/service/Sample?wsdl");
  3. AexampleDemoWebServiceSoap ss = new AexampleDemoWebServiceSoap(wsdlURL, SERVICE_NAME);
  4. //通过HandlerResolver添加Handler
  5. ss.setHandlerResolver(new HandlerResolver(){
  6.  
  7. @Override
  8. @SuppressWarnings("rawtypes")
  9. public List<Handler> getHandlerChain(PortInfo portInfo) {
  10. List<Handler> handlerChain = new ArrayList<Handler>();
  11. handlerChain.add(new JaxWsClientHandler());
  12. return handlerChain;
  13. }
  14.  
  15. });
  16. AExampleDemoWebService port = ss.getSample();
  17. port.querySingle("2222");

服务端 @HandlerChain 注解替代 

  服务发布时服务端通过继承至 Endpoint 实现类 EndpointImpl 的 setHandlers 方法添加头部信息 代替 @HandlerChain 注解 导入 Handler 配置文件

  1. import java.util.ArrayList;
  2. import java.util.List;
  3.  
  4. import javax.xml.ws.Endpoint;
  5. import javax.xml.ws.handler.Handler;
  6.  
  7. import org.apache.cxf.Bus;
  8. import org.apache.cxf.bus.spring.SpringBus;
  9. import org.apache.cxf.interceptor.Interceptor;
  10. import org.apache.cxf.jaxws.EndpointImpl;
  11. import org.apache.cxf.message.Message;
  12. import org.apache.cxf.transport.servlet.CXFServlet;
  13. import org.springframework.boot.context.embedded.ServletRegistrationBean;
  14. import org.springframework.context.annotation.Bean;
  15. import org.springframework.context.annotation.Configuration;
  16.  
  17. @Configuration
  18. public class CXFConfig {
  19.  
  20. @Bean
  21. public ServletRegistrationBean dispatcherServlet() {
  22. return new ServletRegistrationBean(new CXFServlet(), "/service/*");
  23. }
  24.  
  25. @Bean(name = Bus.DEFAULT_BUS_ID)
  26. public SpringBus springBus() {
  27. return new SpringBus();
  28. }
  29.  
  30. @Bean
  31. public AExampleDemoWebServiceImpl aExampleDemoWebServiceImpl() {
  32. return new AExampleDemoWebServiceImpl();
  33. }
  34.  
  35. @Bean
  36. public Endpoint endpointWebServiceSampleImpl() {
  37.  
  38. EndpointImpl endpoint = new EndpointImpl(springBus(), aExampleDemoWebServiceImpl());
  39.  
  40. // SOAPHandler 方式
  41. @SuppressWarnings("rawtypes")
  42. List<Handler> handlers = new ArrayList<>();
  43. handlers.add(new JaxServerAuthValidateHeader());
  44. endpoint.setHandlers(handlers);
  45.  
  46. endpoint.publish("/Sample");
  47.  
  48. return endpoint;
  49.  
  50. }
  51.  
  52. }

当使用替代方式添加头部信息的时候就不需要使用 @HandlerChain 注解 

JAX-WS使用Handler实现简单的WebService权限验证的更多相关文章

  1. 一个简单的webservice的demo(下)winform异步调用webservice

    绕了一大圈,又开始接触winform的项目来了,虽然很小吧.写一个winform的异步调用webservice的demo,还是简单的. 一个简单的Webservice的demo,简单模拟服务 一个简单 ...

  2. 一个简单的Webservice的demo,简单模拟服务

    前段时间一直在学习WCF,匆匆忙忙的把<WCF全面解析>和<WCF服务编程>看了一遍,好多东西都不是很懂,又听了一下WCF分布式开发的网络教程,算是马马虎虎的明白点了.回顾了一 ...

  3. 一个简单的webservice调用

    我们先创建一个简单空web应用程序 然后添加新建项目 //我们创建一个peson对象,产生数据标识返回 using System; using System.Collections.Generic; ...

  4. 利用Java编写简单的WebService实例

    使用Axis编写WebService比較简单,就我的理解,WebService的实现代码和编写Java代码事实上没有什么差别,主要是将哪些Java类公布为WebService. 以下是一个从编写測试样 ...

  5. 利用Java编写简单的WebService实例-转载

    使用Axis编写WebService比较简单,就我的理解,WebService的实现代码和编写Java代码其实没有什么区别,主要是将哪些Java类发布为WebService.下面是一个从编写测试例子到 ...

  6. 一个简单的Webservice的demo(中)_前端页面调用

    首先新建项目,这里有两种调用方式,为了能方便理解,新建页面WebserviceTest如下图: 先引用写好的服务,这里用上次写好的服务.见上次写的一个简单的Webservice的demo,简单模拟服务 ...

  7. 一个简单的WebService实例

    WebService在.NET平台下的作用是在不同应用程序间共享数据与数据交换. 要达到这样的目标,Web services要使用两种技术: XML(标准通用标记语言下的一个子集):XML是在web上 ...

  8. (转)Web Service入门简介(一个简单的WebService示例)

    Web Service入门简介 一.Web Service简介 1.1.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从I ...

  9. 利用VS2008发布一个简单的webservice

    一个开发好的webservice,怎样发布出去,供其他电脑访问呢? 本文将介绍如何发布一个简单的webservice,其中的内容都是在网上查看别人文章,自己仿照着做了一遍,因此,难免会发生错误,如果发 ...

随机推荐

  1. Android onConfigurationChanged 不执行

    自从Android 3.2(API 13),screen size也开始跟着设备的横竖切换而改变. 所以,在AndroidManifest.xml里设置的MiniSdkVersion和 TargetS ...

  2. 数字锁相环Octave仿真

    clc; clear all; % 仿真数据长度 SimLens = 1000; % 载波信号 Fs = 2400; Ts = 1 / Fs; Fsig = 60; % 随机初相 Delta_Phas ...

  3. 数学图形(2.23)Cylindric sine wave柱面正弦曲线

    柱面正弦曲线 #http://www.mathcurve.com/courbes3d/couronnetangentoidale/couronnetangentoidale.shtml vertice ...

  4. STM32+IAP方案 实现网络升级应用固件

    关注了这个概念有些日子了,这段时间总算有机会实战==网络升级应用固件,这里记录下遇到的问题,及解决方案. 原理与网上流传的串口作为传输手段 一致:不同之处,无非我这里使用了网络设备传输.==(lwip ...

  5. Java实现图片的裁剪

    需求: 有一张位置大小的图片,现在需要根据这张原图得到指定尺寸的图片,且得到的图片要符合原先图片的比例,就是在原图的基础上等比例缩放得到图片后,在进行剪裁,这样保证得到的图片是原图的一部分,而不是将原 ...

  6. Understanding the JavaScript Engine—— two phase

    Understanding the JavaScript Engine — Part 1   I have been a Ruby on Rails developer for the last 2 ...

  7. Android MVP 构架初试

    目前讨论MVP MVVM 的架构也来越多,这种构架也很适合Android.研究MVP记录如下 源码地址RxMVP分支Tag02 原有的MVC构架 刚开始接触Android的时候会觉得Android的整 ...

  8. asp.net 输出微信自定义菜单json

    这里使用LitJson.dll作json解析. 微信规定的自定义菜单json样式如下: { "button":[ { "type":"click&qu ...

  9. swift 音乐播放器项目-《lxy的杰伦情歌》开发实战演练

    近期准备将项目转化为OC与swift混合开发.试着写一个swift音乐播放器的demo,体会到了swift相对OC的优势所在.废话不多说.先上效果图: watermark/2/text/aHR0cDo ...

  10. Java程序员的C++回归路(二)

    接前: 之前记录的笔记,终于想起来上传完整. 第7章: 类 定义抽象数据类型 任何对成员对象的访问都可以解释为使用this来访问,即this->member. =default :默认构造函数. ...