使用Spring Webservices构建SOAP Webservices代理模块

前一段时间,我想看看使用Spring Web Services编写Web服务代理(wsproxy)有多么容易。 所以,我想我会在Github上分享结果。 可以随意使用它 (Apache v2许可证)或将其用作自己开发的基础。 本文的其余部分将解释该思想,如何使用Spring Web服务构建它以及有关如何使用当前实现的简短指南。

在此上下文中,wsproxy是中央肥皂感知访问层,可在系统之间中继消息。 这种中继在两个方向上起作用。 对于内部托管的服务(入站模式),对于外部托管的服务,我们都是客户端(出站模式)。 可以将其与传统的HTTP正向/反向代理进行比较,但它无需在应用程序传输上进行操作,而是在堆栈中上移了一层,处理应用程序消息。 在这种情况下,肥皂。

在出站模式下,我们的内部服务(通常)将wsproxy用作http转发代理。 然后它将处理将收到的消息传递到实际目标。 对于入站模式,该模块将充当反向代理,接受来自外部客户端的传入消息,并将其中继到我们的内部服务。

在继续之前,请先介绍一下正向/反向代理:

除了指定目标URL外,转发代理是客户端显式配置的内容。 客户端的http堆栈将消息发送到配置的代理,并通过http标头(主机标头)发送实际所需目标主机的主机/端口。 然后,代理将请求转发到所需的目标主机/端口,并将响应返回给客户端。 因此,代理从http Host标头中组成目标URL的主机和端口。 对于路径,它将使用从客户端收到的请求中的路径。 反向代理的行为(从客户端的角度而言)是实际的目标服务器。 客户端不知道任何代理,也不需要配置任何特殊的东西。 客户端用作目标URL的是反向代理的URL。 反向代理将能够拦截来自客户端的消息,并将其转发到网络中的实际目标。 反向代理将需要额外的配置,例如目标服务的URL(主机,端口和可能的路径),因为无法从请求或HTTP标头中推断出主机/端口。

使用此模块时,仍然可以在边界上实现实际的HTTP反向代理,以实现TLS卸载或其他传输目的。 对于外部入站流量(来自发往内部服务的外部客户端的消息),wsproxy模块将只是进入请求中的第二个反向代理。 对于内部出站流量(来自内部客户端的消息,这些消息发往外部端点),http反向代理的URL将被配置为wsproxy模块上该特定服务的目标URL。

具有这种肥皂感知性的wsproxy的特征之一是集中关注点。 目的是可以拦截通过的肥皂流量。 通过这种方式,我们可以实现诸如审核日志记录,监视,访问控制,消息安全性之类的功能……这样,我们就可以创建一个集中的位置来处理这些需求,而不必针对每个应用程序重新实现它们。

wsproxy用法

我之所以选择Spring Web服务,是因为没有复杂的基础架构或设计需要理解。 它也非常可扩展,并且可以根据我们的要求在适当的级别上重复使用。

但是,此时我还应该指出,现有的解决方案也可以做到这一点,甚至更多。 它们通常以xml安全网关的名义出现,并以软件包或功能齐全的设备的形式出现。 与往常一样,与自己编写某些东西相比,您应该超过这些现有解决方案的好处。 事实是,它们不是免费提供的(至少可以说),并且您仍然需要具有正确技能的人员来配置和维护它们。 正如我们将看到的,只需一点代码(并在Spring Web Services的帮助下)即可轻松满足我们的要求,从而为我们提供所需的所有控制。

对于这些要求,我考虑到了以下开箱即用的要求,因此很容易扩展设计:

  • 对于标准用法,出站模式需要免费配置。 这意味着当需要访问新的外部服务时,我们的代理应该中继消息而无需进行额外的配置
  • 通过网关的消息需要记录。 如果没有额外的配置,则默认情况下应记录整个消息。 (可选)我们需要能够配置更细粒度的特定服务需要记录的部分
  • 对于(主要是外部)出站通信,我们应该能够配置正向代理或使用预先配置的主机(现有的反向代理或实际端点)覆盖目标
  • 万一没有用于卸载出站安全传输的外部反向代理,该模块必须能够通过安全传输转发消息。 对于入站安全传输,我们将通过运行模块的容器来处理此问题。 所以这超出了模块的范围
  • 能够应用和处理消息的完整性/机密性

组件设计如下所示:

wsproxy组件

有3个主要组成部分。 终结点 (图中的全部终结点),它将充当发送到wsproxy的消息的接收者。 转发器 ,它将转发消息到目标。 最后,拦截器链是挂钩,我们可以在其中拦截发送/接收的消息并对其进行处理。

这3个组件由Spring Web Services提供。 终点是实现org.springframework.ws.server.endpoint.MessageEndpoint能够接收原始有效载荷的org.springframework.ws.server.endpoint.annotation.Endpoint。 转发器使用org.springframework.ws.client.core.WebServiceTemplate ,拦截器链是org.springframework.ws.client.support.interceptor.ClientInterceptor和/或org.springframework.ws.server.EndpointInterceptor,具体取决于它们需要哪一边发挥作用(稍后再介绍)。 为了消息安全,我们将使用WSS4J,但这只是拦截器的实现,因此不是新组件。

重要的是要意识到有两个拦截器链。 从wsproxy的角度来看,我们将第一个称为“入站链”。 这是在客户端和wsproxy之间进行的操作。 “出站链”是在wsproxy和目标端点之间运行的链。 因此,如果我们有一个内部客户端通过wsproxy访问外部端点,则wsproxy收到消息后,将调用入站链。 从wsproxy将消息中继到目标端点的那一刻起,将调用出站链。 Spring有两个接口来区分拦截器在哪个“侧面”上运行(拦截器还可以实现两个接口,从而使其能够在两个侧面上都起作用)。 org.springframework.ws.server.EndpointInterceptor在端点侧运行,对于wsproxy而言是入站的。 org.springframework.ws.client.support.interceptor.ClientInterceptor在客户端运行,因此对于wsproxy来说是出站的。 顺便说一句; 我们使用入站和出站,而不是原始的Spring命名(客户端/端点),以避免混淆。 正如您现在所注意到的,wsproxy也是端点和客户端。 但是,当我们提到“客户端”时,是指实际的服务客户端,而“端点”是实际的目标服务。

该模块本身将作为典型的Spring应用程序在标准JEE servlet容器上运行。 对于所有入站流量,都使用容器中的http(或https)连接器。 对于所有出站流量,使用WebServiceTemplate并在其内部配置了commons httpclient,如果需要,我们可以将其同时用于http和https。 服务识别以“ doclit”样式完成。 这意味着我们采用主体的第一个元素,包括其名称空间。 这表示为QName 。 此标识非常重要,因为我们将基于每个服务进行配置,例如转发代理,转发协议,端点URL映射,特定记录器等。

够了。 让我们带这个宝贝去兜风吧! 在您选择的IDE中导入项目,请确保将其导入为Maven项目,因为Maven必须过滤文件active_environment.properties (通过默认配置文件自动完成)。 然后,我们将:

  • 设置一个基于普通独立肥皂的端点
  • 部署wsproxy
  • 使用Web服务客户端通过代理模块访问端点

为了引导简单端点,在测试源中预见到一个类SimpleEndpoint ,该类使用JDK内部JAX-WS和http服务器来引导Web服务端点:

public class SimpleEndpoint {public static void main(String args[]) {Endpoint.publish("http://localhost:9999/simple", new SimpleWebServiceEndpoint());}@WebServicepublic static class SimpleWebServiceEndpoint {public Date getCurrentDate(String randomParameter) {return new Date();}}
}

只需将其作为新的Java应用程序运行,它将一直运行,直到进程被杀死。 通过将项目部署到您选择的服务器(我将使用Tomcat7)来启动wsproxy,不需要任何额外的配置。 对于客户端,我们将使用soap-ui(如果愿意,也可以使用cURL)。 在soap-ui中,我们首先必须创建项目。 我们基于测试服务公开的WSDL(可从http:// localhost:9999 / simple?WSDL访问)进行此操作。 接下来,我们必须将wsproxy模块配置为soap-ui中的HTTP转发代理:

soap-ui-2 soap-ui-1

如果需要, 在项目中也可以使用soap-ui项目。 别忘了启用上述代理设置,它们不会保存为项目的一部分。

重要提示:如果您要开始一个新项目,请不要忘记再次禁用代理设置。 soap-ui将使用代理设置来处理标准的http流量,而不仅用于soap / http。 例如; 当基于WSDL URL创建新项目时,soap-ui还将使用http代理设置来检索WSDL。 由于wsproxy模块不是纯HTTP代理(而是肥皂代理),因此它将不允许非肥皂流量通过。

我们需要配置的最后一件事是soap-ui中的目标URL。 默认情况下(至少在tomcat上)部署wsproxy模块,该上下文根以文件名命名。 在我们的情况下,这意味着该模块在以下位置可访问:http:// localhost:8080 / ws-proxy /
有两种选择:

  • 而是将模块部署在应用程序服务器(/)的根目录下。 在这种情况下,无需将任何内容更改为目标URL。 目标网址将与没有代理模块时将使用的网址相同
  • 使用选择的上下文根,但是在这种情况下,您必须在上下文根之前添加目标URL

在第二种情况下,这意味着我们必须将建议的目标URL从“ http:// localhost:9999 / simple”更改为“ http:// localhost:9999 / ws-proxy / simple ”。

发生的是soap-ui将请求发送到代理设置中指定的主机/端口(因此,它不会将请求发送到localhost:9999,而是发送到localhost:8080)。 但是,路径保留了下来。 该请求实际上通过路径“ ws-proxy / simple”发送到localhost:8080。 通过将模块部署在“ ws-proxy”下,您现在可以了解为什么必须在此路径前缀。 如果路径以“ simple”开头,则将得到404。路径的其余部分对于基础结构并不重要,因为Spring调度程序servlet(配置可以在WsProxyWebApplicationInitializer中找到)绑定到“ / *”。 因此,每种情况下,servlet都会处理每个后续路径。

为了能够将消息转发到实际目标,模块将计算目标URL:

  • 首先根据服务标识(有效负载根元素+名称空间)检查给定端点是否有预先配置的目标URL。 这是在EndpointTargetUrlMapping中配置的,我们将在后面看到。
  • 如果未找到任何内容,请检查是否存在http Host标头,并将host:port用作目标服务器。 对于路径,请使用请求中存在的路径,但减去在其中部署此模块的上下文根(如果有)

后者意味着在我们的示例中,模块部署在“ ws-proxy”下,请求路径为“ ws-proxy / simple”,这将导致目标URL为“ http:// localhost:999 / simple”。执行请求,我们将得到以下答案:

soap-ui-4

在wsproxy日志文件中,我们可以看到截获的请求和响应正在记录:

51948 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.interceptors.internalchain.LoggingInterceptor  - SID:{http://wsproxy.error.be/}getCurrentDate INBOUND SIDE Request:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsp="http://wsproxy.error.be/"><soapenv:Header/><soapenv:Body><wsp:getCurrentDate><!--Optional:--><arg0>?</arg0></wsp:getCurrentDate></soapenv:Body>
</soapenv:Envelope>51949 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.core.ForwardingClient  - Using information from Host header as hostname/port
51949 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.core.ForwardingClient  - Got webservice forwarding request, sending to:http://localhost:9999/simple
51981 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.core.ForwardingClient  - Using interceptors:[class be.error.wsproxy.interceptors.externalchain.HttpRequestHeaderTransfererInterceptor]
51981 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.core.ForwardingClient$3  - Opening [org.springframework.ws.transport.http.HttpComponentsConnection@1dd5e19a] to [http://localhost:9999/simple]
51991 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.core.ForwardingClient  - Forwarding (http://localhost:9999/simple) done.
51994 [http-bio-8080-exec-5] DEBUG be.error.wsproxy.interceptors.internalchain.LoggingInterceptor  - SID:{http://wsproxy.error.be/}getCurrentDate INBOUND SIDE Response:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getCurrentDateResponse xmlns:ns2="http://wsproxy.error.be/"><return>2013-10-28T15:55:29.717+01:00</return></ns2:getCurrentDateResponse></S:Body>
</S:Envelope>

在默认设置中,默认日志记录发生在入站侧。 入站拦截器在这里配置:

@Configuration
public class InboundInterceptors {@Autowiredprivate PayloadRootAnnotationMethodEndpointMapping catchAllEndpointMapping;@Autowiredprivate MessageDispatcher messageDispatcher;@Configurationpublic static class FirstInlineInterceptors {@Beanpublic DelegatingSmartSoapEndpointInterceptor loggingInterceptor() {return new DelegatingSmartSoapEndpointInterceptor(new LoggingInterceptor());}}@Configurationpublic static class ServiceSpecificInterceptors {}@Configurationpublic static class LastInLineInterceptors {}
}

如果要在出站侧也配置此日志记录拦截器,则可以将它们添加到OutboundInterceptors中 。 LoggingInterceptor都实现EndpointInterceptorClientInterceptor 。 为了满足我们的要求,还有一个拦截器,该拦截器能够基于XPath表达式记录片段。 LoggingXPathInterceptor是特定于服务的,因此,我们会将其添加到ServiceSpecificInterceptor中。 不同之处在于,特定于服务的拦截器使用PayloadRootSmartSoapEndpointInterceptor ,我们需要提供命名空间和有效负载根元素来标识服务。 配置的拦截器将仅针对该服务被调用。 首次使用和最后使用
DelegatingSmartSoapEndpointInterceptor ,将为任何请求调用。

@Configurationpublic static class ServiceSpepcificInterceptors {@Beanpublic PayloadRootSmartSoapEndpointInterceptor getCurrentDateLoggingInterecptor() {LoggingXPathInterceptor loggingXPathInterceptor = new LoggingXPathInterceptor();loggingXPathInterceptor.addRequestXPaths(new WebServiceMessageXPathExpressionMetaData("//*[local-name()='arg0']", "requestParameter"));loggingXPathInterceptor.addResponseXPaths(new WebServiceMessageXPathExpressionMetaData("//*[local-name()='return']", "responseParameter"));return new PayloadRootSmartSoapEndpointInterceptor(loggingXPathInterceptor, "http://wsproxy.error.be/","getCurrentDate");}}

当我们在soap-ui中再次执行请求时,我们可以看到将请求参数和响应值提取到日志文件中:

DEBUG be.error.wsproxy.interceptors.internalchain.LoggingXPathInterceptor - SID:{http://wsproxy.error.be/}getCurrentDate XPATHID:requestParameter VALUE:?
DEBUG be.error.wsproxy.interceptors.internalchain.LoggingXPathInterceptor - SID:{http://wsproxy.error.be/}getCurrentDate XPATHID:responseParameter VALUE:2013-10-28T16:50:29.537+01:00

WebServiceMessageXPathExpressionMetaData默认情况下在肥皂主体(有效负载)上运行,并将给定的XPath视为强制性(但非阻塞性)。 要查看其他选项,请检查WebServiceMessageXPathExpressionMetaData上的javadoc。

可以配置的属性位于包be.error.wsproxy.configuration.properties中 。 存在以下类:

  • 端点协议映射
  • EndpointTargetUrlMapping
  • 转发代理
  • 密钥库

通过默认的Maven过滤器Maven启用的默认Spring配置文件“本地”将通过以下属性文件解析它们:
wsproxy_local_demo.properties 。 配置始终存储为简单的字符串,以便在例如JNDI环境中轻松进行外部化。 从EndpointProtocolMapping开始,前三个属性确定如何转发消息:

在上述情况下,由于我们的内部客户端将模块用作转发代理,因此从Host参数自动推导出了目标URL。 由于主机参数不包含有关协议的任何概念,因此默认情况下,wsproxy会将http假定为转发协议。 如果没有负责减轻TLS负担的反向代理,则可以要求代理模块通过https转发。 您可以通过将特定服务的协议映射设置为https来做到这一点:

endpoint.protocol.mapping={namespace}payloadRootElementLocalName=https,...

EndpointTargetUrlMapping允许直接定义目标URL。 在外部客户端将访问我们的内部服务的情况下,这是必需的。 在这种情况下,无法再推导目标URL。 外部客户端将不会使用我们的模块作为转发代理,但是该消息只会作为实际服务最终出现在我们的模块上。 然后,模块需要知道将消息转发到的位置:

endpoint.target.url.mapping={namespace}payloadRootElementLocalName=http(s)://host:port/path,....

这也可以用于一起覆盖目标URL。 转发器将首先查看是否有为给定服务定义的显式URL,如果是,则将为该URL赋予优先级。

当wsproxy模块需要通过http转发代理进行通信才能到达目标时,可以配置ForwardProxy。 也可以基于每个服务进行配置。

wsproxy-proxy
请记住,前向代理不会改变目标URL的计算方式。 如果使用该设置,则消息将转发到已配置的代理,而不是直接访问目标URL:

forward.proxy=={namespace}payloadRootElementLocalName=host:port,...

密钥库指向包含商店位置,商店密码,密钥别名和密钥密码的密钥库配置。 当我们要应用消息安全性时将使用它们,我们将在后面讨论。

keystores.location=${project.root.dir}/config/test-keystores
keystore=${keystores.location}/keystore.jks
keystore.password=changeme
key.alias=mykey
key.password=changeme
truststore=${keystores.location}/truststore.jks
truststore.password=changeme

为了满足最后一个要求(完整性/机密性),我们将通过Spring Wss4jSecurityInterceptor使用WSS4J。 在我们的示例中,如果我们有内部客户端访问外部服务,则需要在出站侧配置此拦截器。 我们将执行的步骤:

  • 设置安全的基于独立Soap的端点
  • 为给定服务配置具有消息安全性的wsproxy
  • 部署wsproxy
  • 使用Web服务客户端通过代理模块访问端点

对于安全端点,可以使用JAXWS和WSIT预测SimpleSecuredEndpoint 。 可以在META-INF / wsit-be.error.wsproxy.SimpleSecuredEndpoint $ SimpleWebServiceEndpoint.xml中找到WSIT配置,以在端点上启用消息完整性。

public class SimpleSecuredEndpoint {public static void main(String args[]) throws IOException {// Set WSIT_HOME manually, we're only using this for testing purposes. This way we can have a dynamic path based// on the project location in filesystem to resolve the keystores via the WSIT configuratin in META-INFSystem.setProperty("WSIT_HOME", new ClassPathResource("").getFile().getParent() + "/../config/test-keystores/");Endpoint.publish("http://localhost:9999/simple", new SimpleWebServiceEndpoint());}@WebService(serviceName = "SimpleEndpoint")@Addressing(enabled = false, required = false)public static class SimpleWebServiceEndpoint {public Date getCurrentDateSecured(String randomParameter) {return new Date();}}
}

重要: JDK附带的JAXWS实现不包含WSIT。 它只是JAXWS RI。 为了使它起作用,您必须自己下载最新的Metro版本,它将所有内容捆绑在一起。 参见Metro主页 。 下载Metro后,运行SimpleSecuredEndpoint并附带已认可的系统属性: -Djava.endorsed.dirs = / path_to_metro / lib 。 这将确保从外部库中使用整个JAXWS实现。 当一切运行正常时,您会看到一条线:

INFO: WSP5018: Loaded WSIT configuration from file: file:/home/koen/....


WSS4J拦截器的配置可在OutboundInterceptors中实现消息完整性:

@Beanpublic Map<QName, List<ClientInterceptor>> customClientInterceptors() throws Exception {Map<QName, List<ClientInterceptor>> mapping = new HashMap<>();List<ClientInterceptor> list = new ArrayList<>();list.add(getCurrentDateServiceSecurityInterceptor());list.add(new LoggingInterceptor());mapping.put(new QName("http://wsproxy.error.be/", "getCurrentDateSecured"), list);return mapping;}private Wss4jSecurityInterceptor getCurrentDateServiceSecurityInterceptor() throws Exception {Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();// Outgoinginterceptor.setSecurementActions("Signature Timestamp");interceptor.setSecurementSignatureParts("{}{http://schemas.xmlsoap.org/soap/envelope/}Body;{}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp");interceptor.setSecurementSignatureKeyIdentifier("IssuerSerial");Pair<String, String> key = keystore.getKeyAliasPasswords().get(0);interceptor.setSecurementUsername(key.getLeft());interceptor.setSecurementPassword(key.getRight());interceptor.setSecurementSignatureAlgorithm("http://www.w3.org/2000/09/xmldsig#rsa-sha1");interceptor.setSecurementSignatureDigestAlgorithm("http://www.w3.org/2000/09/xmldsig#sha1");interceptor.setSecurementTimeToLive(700);interceptor.setValidationTimeToLive(700);interceptor.setSecurementSignatureCrypto(keystoreCrypto);// Incomminginterceptor.setValidationActions("Timestamp Signature");interceptor.setValidationSignatureCrypto(truststoreCrypto);return interceptor;}

在第6行和第7行,我们将自定义拦截器添加到ForwardingClient使用的拦截器列表中。 我们还在出站上添加了LoggingInterceptor,以便可以看到受保护的消息传出和传入。要测试消息安全配置,请部署wsproxy并使用soap-ui触发请求。 soap-ui设置与非安全端点的设置没有什么不同。

重要提示: C14N似乎有问题。 当请求正常发送时,WSIT将抱怨计算的摘要与消息中的摘要不匹配。 我将对此进行进一步调查,但这似乎是WSIT而不是WSS4J的问题,因为当soap-ui配置为安全客户端并直接与端点进行通信而不是使用wsproxy模块时,也会发生相同的问题。 要解决此问题并查看测试工作,请删除soap Body起始元素和有效负载根起始元素之间的换行。 还要删除皂体末端元素和有效负载根末端元素之间的换行符:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsp="http://wsproxy.error.be/"><soapenv:Header/><soapenv:Body><wsp:getCurrentDateSecured><!--Optional:--><arg0>?</arg0></wsp:getCurrentDateSecured></soapenv:Body>
</soapenv:Envelope>

如果需要, 在项目中也可以使用soap-ui项目。 别忘了启用代理设置,如前所述,它们不会保存为项目的一部分。

结果:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:exc14n="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"><S:Header/><S:Body wsu:Id="_5002"><ns2:getCurrentDateSecuredResponse xmlns:ns2="http://wsproxy.error.be/"><return>2013-10-29T14:26:25.789+01:00</return></ns2:getCurrentDateSecuredResponse></S:Body>
</S:Envelope>

wsproxy在转发请求时增加了消息安全性,而在返回响应时将其删除了,这并不奇怪。 如果我们查看wsproxy日志文件,首先将看到在inboud端输入的请求:

34   [http-bio-8080-exec-3] DEBUG be.error.wsproxy.interceptors.logging.LoggingInterceptor  - SID:{http://wsproxy.error.be/}getCurrentDate INBOUND SIDE Request:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsp="http://wsproxy.error.be/"><soapenv:Header/><soapenv:Body><wsp:getCurrentDateSecured><!--Optional:--><arg0>?</arg0></wsp:getCurrentDateSecured></soapenv:Body>
</soapenv:Envelope>

该请求被保护并转发到端点:

394  [http-bio-8080-exec-3] DEBUG be.error.wsproxy.interceptors.logging.LoggingInterceptor  - SID:{http://wsproxy.error.be/}getCurrentDate OUTBOUND SIDE Request:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsp="http://wsproxy.error.be/"><soapenv:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soapenv:mustUnderstand="1"><wsu:Timestamp wsu:Id="TS-518848887F924441AB13830540361321"><wsu:Created>2013-10-29T13:40:36.130Z</wsu:Created><wsu:Expires>2013-10-29T13:45:36.130Z</wsu:Expires></wsu:Timestamp><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-518848887F924441AB13830540361916"><ds:SignedInfo>
...

从端点接收到安全响应;

524  [http-bio-8080-exec-3] DEBUG be.error.wsproxy.interceptors.logging.LoggingInterceptor  - SID:{http://wsproxy.error.be/}getCurrentDate OUTBOUND SIDE Response:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:exc14n="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"><S:Header><wsse:Security S:mustUnderstand="1"><wsu:Timestamp xmlns:ns15="http://www.w3.org/2003/05/soap-envelope" xmlns:ns16="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" wsu:Id="_3"><wsu:Created>2013-10-29T13:40:36Z</wsu:Created><wsu:Expires>2013-10-29T13:45:36Z</wsu:Expires></wsu:Timestamp><ds:Signature xmlns:ns15="http://www.w3.org/2003/05/soap-envelope" xmlns:ns16="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" Id="_1"><ds:SignedInfo>
...

安全信息得到处理和验证。 如果可以,则剥离安全信息并返回响应(在这种情况下,返回给我们的客户端soap-ui):

567  [http-bio-8080-exec-3] DEBUG be.error.wsproxy.interceptors.logging.LoggingInterceptor  - SID:{http://wsproxy.error.be/}getCurrentDate INBOUND SIDE Response:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:exc14n="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"><S:Header/><S:Body wsu:Id="_5002"><ns2:getCurrentDateSecuredResponse xmlns:ns2="http://wsproxy.error.be/"><return>2013-10-29T14:40:36.357+01:00</return></ns2:getCurrentDateSecuredResponse></S:Body>
</S:Envelope>

到目前为止,已经完成了所有模拟内部客户端访问外部服务的测试。 如果您想使用模块做逆运算; 服务外部客户端访问内部托管的服务,情况更多。 对于模块将转发到的每个内部托管服务,您必须使用endpoint.target.url.mapping配置参数注册目标URL。 拦截器继续以相同的方式工作,但是请记住,例如,出于消息安全性,您可能希望在入站侧配置Wss4jSecurityInterceptor,因为在这种情况下,入站侧是面向外部的一侧。 在入站和出站侧为不同的服务配置Wss4jSecurityInterceptor没问题; 所有配置均基于每个服务。

例如:服务x(由名称空间和有效负载根元素标识)是内部托管服务。 服务y是内部客户端要访问的外部服务。 为了保护内部服务x,我们将在InboundInterceptors配置中添加Wss4jSecurityInterceptor作为服务特定的入站拦截器。 因此,此拦截器将仅在wsproxy端点上处于活动状态(仅服务于入站侧,在此示例中为面向外部的侧),并且仅对于服务x有效。 为了保护对服务y的调用,我们将在OutboundInterceptors中注册Wss4jSecurityInterceptor,为wsproxy模块发送到外部服务y的消息增加消息安全性。

好的,就是这样! 如果这对您有用,或者您有改进的想法,请随时给我留言。

参考:位于Koen Serneels – Technology博客博客上的JCG合作伙伴 Koen Serneels 使用Spring Webservices构建SOAP Webservices代理模块 。

翻译自: https://www.javacodegeeks.com/2013/11/building-a-soap-webservices-proxy-module-using-spring-webservices.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366509.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

joc杂志影响因子2019_排名 ‖ 2019年中国体育学期刊影响因子

近日&#xff0c;由中国科学文献计量评价研究中心、清华大学图书馆研制&#xff0c;《中国学术期刊&#xff08;光盘版&#xff09;》电子杂志社有限公司出版的《中国学术期刊影响因子年报》&#xff08;2019版&#xff09;发布。该年报是中国科学文献计量评价研究中心自2002年…

Confluence 6 MySQL 3.x 字符集编码问题

MySQL 3.x is 已知在大写和小写转换的时候有些问题&#xff08;non-ASCII&#xff09;。 问题诊断 请按照 Troubleshooting Character Encodings 页面中的内容对问题进行诊断。如果大小写字符串编码诊断显示不同&#xff0c;那么有可能是你数据库导致的。一个错误的数据库大小写…

手型向下 点击一下 福昕_PPT多张缩略图点击放大展示

↑点击上方“菜鸟PPT”关注&#xff0c;教你玩转PPT&#xff01;多张图片单击放大展示&#xff0c;以前做过一个比较复杂的&#xff0c;在同一页PPT里面做&#xff0c;加了很多个“进入”和“退出”的动画&#xff0c;维护起来比较麻烦。今天&#xff0c;菜鸟菌跟大家一起来学习…

6个经典的JavaScript报错分析

代码报错是经常发生的一件事&#xff0c;我们要确定是什么原因造成的&#xff0c;以及如何避免错误。 1. Uncaught TypeError: Cannot read property 该错误说明没有某个属性&#xff0c;一般是该属性前面的值是undefined或者是null的情况会出现。 2. TypeError: ‘undefined…

git显示服务器所有分支,git 查看所有远程分支以及同步

在多台电脑使用git管理开发分支的时候&#xff0c;会出现这样的情况。电脑A创建了分支1&#xff0c;并且push上了远程仓库。电脑B本地clone仓库默认只会clone下master分支&#xff0c;而其他电脑A推送的分支是不会默认同步下来的。那么如何同步呢&#xff1f;查看电脑B本地仓库…

json-schema 可视化编辑器发布了

json-schema 的用途越来越广泛&#xff0c;除了定义数据结构外&#xff0c;我们还可以使用 json-schema 验证数据格式和生成随机数据&#xff0c;但是编写复杂数据结构的 json-schema 是非常痛苦的事情。假设一个 100 字段的数据结构&#xff0c;如果用 json-schema 定义&#…

tfw文件如何导入cad_如何将CAD的线稿导入PS并和底色分离

【新朋友】 点击标题下方的 CG伴学 迅速关注【老朋友】 点击右上角的按钮 分享 或者 收藏这是 【CG伴学 】制作的第249篇答疑教程观看往期视频教程请点击或者前往公众号自定义菜单【学习中心】我们专门制作了教程汇总目录&#xff0c;你可以根据标题关键词搜索获取我们在后台收…

Python全栈工程师(函数嵌套、变量作用域)

ParisGabriel 感谢 大家的支持 每天坚持 一天一篇 点个订阅吧 灰常感谢 当个死粉也阔以 Python人工智能从入门到精通 globals&#xff08;&#xff09;/locals&#xff08;&#xff09;函数&#xff1a;     globals&#xff08;&#xff09;返回当前全局作用域内变量…

可视化分析js的内存分配与回收

之前写了一篇文章浏览器是怎么看闭包的&#xff0c;发现有些读者对js内存分配与回收懵懵懂懂&#xff0c;理解文章的配图有些困难&#xff0c;我想主要是因为配图省略了一些细节。今天专门写一篇关于js内存分配回收的文章&#xff0c;帮助大家理解js代码的内存表示。原文备份在…

记录程序写入日志_终于有人把MySQL 三大日志讲清楚了

点击上方"蓝字"&#xff0c;关注了解更多日志是 mysql 数据库的重要组成部分&#xff0c;记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。作为开发&#xff0c;我们重点需要关注的是二进制日志( …

在ADF实体PK属性中使用MySQL自动增量PK列

大家好。 继续进行ADF MySQL解决方法系列&#xff0c;今天我们将看到要使用MySQL PK自动增量列和ADF实体PK属性来进行的工作。 如果使用的是Oracle数据库&#xff0c;则可以使用oracle.jbo.domain.DBSequence以及序列和触发器来立即进行操作。 为简单起见&#xff0c;我们将修…

14.正则表达式、re模块、元字符

正则表达式 一、正则表达式所面向的问题 1、判断一个字符串是否匹配给定的格式 判断用户注册帐号是否满足格式 2、从一个字符串中按指定格式提取信息 抓取页面中的链接 二、判断用户提交的邮箱的格式是否正确 三、抓取页面中特定部分数据 er模块 1、findall方法&a…

WeScale 技术篇 —— mpvue 与微信小程序的火花

介绍项目介绍WeScale 定位为音乐训练小程序&#xff0c;初期规划了基础音阶的三个训练&#xff0c;以及他们的镜像模式。数字简谱字母简谱数字简谱对字母简谱后期看情况更新追加其他训练。产品展示扫描下方小程序码或在微信小程序中搜索 WeScale&#xff0c;即可使用。人员介绍…

025 SSM简单搭建

参考了同事的文档&#xff0c;自己也写一篇文档。 同时&#xff0c;补充了一下&#xff0c;程序是如何运行的。 一&#xff1a;SSM框架 1.说明 SSM&#xff08;SpringSpringMVCMyBatis&#xff09;框架集由Spring、SpringMVC、MyBatis三个开源框架整合而成&#xff0c;常作为数…

上升沿_PLC上升沿,下降沿的理解

有网友留言说&#xff1a;上升沿就是在信号从断开到接通的那一瞬间接通&#xff0c;下降沿就是在信号从接通到断开的那一瞬间接通。但是现在的问题它的实际用处是用在哪一些情况。我身边也有PLC可以做个什么实验来体验一下呢&#xff1f;虽然说LD X0 PLS M0与LDP X0 out Y0…

中找不到iedis_CAD图纸中缺少的字体实在找不到怎么办呢?

在使用浩辰CAD软件打开图纸文件的时候经常提示缺少字体这是什么原因呢&#xff1f;怎么解决这个问题呢&#xff1f;其实打开CAD图纸时提示缺少字体是比较常见的情况&#xff0c;但是很多常见的字体也提示缺失是为什么呢&#xff1f;因为这些字体很显然是被人改过名字了&#xf…

1023 Have Fun with Numbers

因为最多有20个字符&#xff0c;int和long long都不行&#xff0c;所以只能用字符串操作。水题~ #include<iostream> #include<algorithm> #include<string.h> #define maxn 25 using namespace std; typedef long long ll; char s1[maxn]; int s2[maxn]; in…

Apache Camel –从头开始开发应用程序(第1部分/第2部分)

开始之前 前一段时间&#xff0c;我写了一篇关于Spring Integration的教程&#xff0c;以演示如何在受现实发票处理系统启发的示例应用程序中使用Spring Integration。 我对此非常满意&#xff0c;因此我决定向您展示如何使用Apache Camel&#xff08;Spring Integration的最大…

杭州 GraphQLParty 第五场-GraphQL 基于 SPA 架构的工程实践文字版

本文为 2018 年 6 月 9 日&#xff0c;宋小菜与 Coding 共同举办的第一届 GraphQLParty &#xff0c;下午第五场国内某大型电商前端开发专家邓若奇的演讲稿&#xff0c;现场反响效果极好&#xff0c;对于想要尝试 GraphQL 和在公司初步实践的团队有很大的借鉴意义。 大家好&…

使用sikuli和Arquillian测试HTML5 canvas应用程序

HTML5引入了一个很棒的新元素&#xff0c;可以用来在窗格上绘制任意内容&#xff1a; canvas元素。 数十年来&#xff0c;胖客户端应用程序的标准功能现已引入Web应用程序领域。 Web开发人员不再需要使用专有插件在其应用程序中绘制图像或图表。 但是&#xff0c;在进行测试时…