java - Spring WebClient 在使用 ExchangeFilterFunction 发送之前无法读取请求正文
问题描述
我一直使用 RestTemplate 并决定切换到 WebClient。
在发送请求之前,我使用私钥签署请求正文,客户端使用公共密钥检查请求。
我的拦截器:
private static class SignatureClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private final PrivateKey privateKey;
private SignatureClientHttpRequestInterceptor(String privateKeyLocation) {
this.privateKey = PemUtils.getPrivateKey(Paths.get(privateKeyLocation));
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
if (request.getMethod() == HttpMethod.POST) {
request.getHeaders().add("X-Signature", Base64.getEncoder().encodeToString(PemUtils.signData(privateKey, SignatureAlgorithm.RS256.getJcaName(), body)));
}
return execution.execute(request, body);
}
}
但是在 WebClient,我没有在 ExchangeFilterFunction 中找到这样的机会。
无论如何要在 WebClient 中执行此操作,还是我必须在发送之前手动签署请求正文?
解决方案
签署正文需要以序列化的形式,但序列化发生在发送数据之前,因此需要以某种方式拦截它。
对于 JSON 内容,您可以创建自己的编码器(Jackson2JsonEncoder
例如包装现有的编码器)并ExchangeStrategies
在构建WebClient
. 截取序列化数据后,可以注入headers。但是编码器没有对 的引用,ClientHttpRequest
因此您需要在 an 中捕获此对象HttpConnector
并将其传递给SubscriberContext
.
这篇博文解释了这个过程: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();
推荐阅读
- wordpress - 更改 Woocommerce My-Account Slug/永久链接
- python - 为什么 crontab 不运行 python 脚本
- javascript - 当源是远程时更改 HTML 音频中的 currentTime?
- javascript - 引用的 JS 文件不会让 HTML 页面获得比第一个常量更多的信息
- c# - 关闭拥有的表单时启用/禁用所有者表单上的按钮
- node.js - 建立从 apache angular app 到 rest api node js 的连接
- function - 本地声明的 lua 函数是否在每次传递时都会被解析?
- flutter - 有多个英雄在子树中共享相同的标签而不使用 FAB
- laravel - Laravel-auth-timeout - 事件和监听器
- rust - Rust:为什么第一个借用后来用在这里?