Spring WebClient:自动计算 body 的 HMAC 签名并将其作为 header 传递
Spring WebClient: Automatically compute HMAC signature for body and pass it as header
在我的 Spring 引导应用程序中,我使用 RestTemplate
调用一个 WS,body HMAC 签名应作为 HTTP header 提供。为此,我使用了 ClientHttpRequestInterceptor
。基本上,我做了:
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
try {
String hmac = Hmac.calculateRFC2104HMAC(body, key);
request.getHeaders().add("X-Hub-Signature", "sha1=" + hmac);
return execution.execute(request, body);
}
catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new IOException(e);
}
}
现在我想使用 WebClient
更好地集成到我的反应式应用程序中。但是我迷失在这个新的反应 API 中。如何使用 ExchangeFilterFunction
或 BodyInserter
实现此目的?困难在于检索 body、执行签名计算并随后更新请求。
感谢您的支持。
签署 body 需要序列化形式,但序列化发生在发送数据之前,因此需要拦截。
您可以通过创建自己的编码器(例如包装现有的 Jackson2JsonEncoder
)并在构建 WebClient
时将其作为 ExchangeStrategies
传递来实现。截取序列化数据后,可以注入headers。但是编码器没有对 ClientHttpRequest
的引用,因此您需要在 HttpConnector
中捕获此 object 并将其传递到 SubscriberContext
.
这篇博客post解释了这个过程:https://andrew-flower.com/blog/Custom-HMAC-Auth-with-Spring-WebClient#s-post-data-signing
例如,您的 WebClient
创建步骤可能如下所示,其中 MessageCapturingHttpConnector
是一个连接器,用于捕获 ClientHttpRequest
和 BodyCapturingJsonEncoder
Signer signer = new Signer(clientId, secret);
MessageSigningHttpConnector httpConnector = new MessageSigningHttpConnector();
BodyCapturingJsonEncoder bodyCapturingJsonEncoder
= new BodyCapturingJsonEncoder(signer);
WebClient client
= WebClient.builder()
.exchangeFunction(ExchangeFunctions.create(
httpConnector,
ExchangeStrategies
.builder()
.codecs(clientDefaultCodecsConfigurer -> {
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(bodyCapturingJsonEncoder);
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
})
.build()
))
.baseUrl(String.format("%s://%s/%s", environment.getProtocol(), environment.getHost(), environment.getPath()))
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
在我的 Spring 引导应用程序中,我使用 RestTemplate
调用一个 WS,body HMAC 签名应作为 HTTP header 提供。为此,我使用了 ClientHttpRequestInterceptor
。基本上,我做了:
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
try {
String hmac = Hmac.calculateRFC2104HMAC(body, key);
request.getHeaders().add("X-Hub-Signature", "sha1=" + hmac);
return execution.execute(request, body);
}
catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new IOException(e);
}
}
现在我想使用 WebClient
更好地集成到我的反应式应用程序中。但是我迷失在这个新的反应 API 中。如何使用 ExchangeFilterFunction
或 BodyInserter
实现此目的?困难在于检索 body、执行签名计算并随后更新请求。
感谢您的支持。
签署 body 需要序列化形式,但序列化发生在发送数据之前,因此需要拦截。
您可以通过创建自己的编码器(例如包装现有的 Jackson2JsonEncoder
)并在构建 WebClient
时将其作为 ExchangeStrategies
传递来实现。截取序列化数据后,可以注入headers。但是编码器没有对 ClientHttpRequest
的引用,因此您需要在 HttpConnector
中捕获此 object 并将其传递到 SubscriberContext
.
这篇博客post解释了这个过程:https://andrew-flower.com/blog/Custom-HMAC-Auth-with-Spring-WebClient#s-post-data-signing
例如,您的 WebClient
创建步骤可能如下所示,其中 MessageCapturingHttpConnector
是一个连接器,用于捕获 ClientHttpRequest
和 BodyCapturingJsonEncoder
Signer signer = new Signer(clientId, secret);
MessageSigningHttpConnector httpConnector = new MessageSigningHttpConnector();
BodyCapturingJsonEncoder bodyCapturingJsonEncoder
= new BodyCapturingJsonEncoder(signer);
WebClient client
= WebClient.builder()
.exchangeFunction(ExchangeFunctions.create(
httpConnector,
ExchangeStrategies
.builder()
.codecs(clientDefaultCodecsConfigurer -> {
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(bodyCapturingJsonEncoder);
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
})
.build()
))
.baseUrl(String.format("%s://%s/%s", environment.getProtocol(), environment.getHost(), environment.getPath()))
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();