0

My question is somewhat similar to Can I access the request/response body on an ExchangeFilterFunction?

I am using declarative Spring Rest Http Interface to call our internal APIs.

For every outgoing request, I have to sign the request and add a signature in the header. The obvious thing is to do this in an exchange filter which is similar to the following.

@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {

    // There is no way I can get request body like in spring mvc
    String requestBody = request.body().toString();
    var signatureValue = signRequest(requestBody);

    // Add the Signature header
    var headers = new HttpHeaders();
    headers.add(“signature”, signatureValue);

    var modifiedRequest = ClientRequest.from(request)
    .headers(httpHeaders -> httpHeaders.addAll(headers)).build();
    
    return next.exchange(modifiedRequest);

}

Since I am not using either restTemplate or webClient directly, I am looking for a way to add the header possibly from a central place. Any idea, suggestion, workaround, or solution is really appreciated.

Regards

pmverma
  • 1,653
  • 13
  • 27

1 Answers1

0

I found a workaround to achieve this by implementing HttpServiceArgumentResolver and overriding resolve method.

The following is how body is read and header is added.

@Component
@RequiredArgsConstructor
public class MySignatureHeaderResolver implements HttpServiceArgumentResolver {
    @Override
    public boolean resolve(@Nullable Object argument, MethodParameter parameter,
            HttpRequestValues.Builder requestValues) {
        Object requestBody = argument;
        RequestBody annot = parameter.getParameterAnnotation(RequestBody.class);
        if (annot == null) {
            requestBody = ""; 
        }
        String signatureValue = signRequest(timestamp + requestBody);
        requestValues.addHeader("signature", signatureValue);
        
        return false; // always return false, otherwise a correct request won't created.
    }
}

And then register this as a custom argument resolver (which is not in actual) to the http proxy factory.

@Bean
    public HttpServiceProxyFactory httpServiceProxyFactory(
            HttpServiceProxyFactory.Builder httpServiceProxyFactoryBuilder) {
        httpServiceProxyFactoryBuilder.customArgumentResolver(mySignatureHeaderResolver);
        return httpServiceProxyFactoryBuilder.build();
    }
pmverma
  • 1,653
  • 13
  • 27