We've been using Spring Cloud Gateway for about 2 years in production. We're in the process of adding rate limiting support but we've run into a road block. One of the key endpoints we want to rate limit is our /oauth2/token endpoint. The trick here is this endpoint has credentials contained in the body that we need for our KeyResolver (to determine alleged identity). So we implemented the following KeyResolver:
public class OAuth2KeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
String ipAddress = exchange.getRequest().getRemoteAddress().getHostName();
ServerRequest serverRequest = ServerRequest.create(exchange,
HandlerStrategies.withDefaults().messageReaders());
return serverRequest.bodyToMono(String.class).flatMap(requestBody -> {
JsonNode json = jackson.readTree(requestBody);
String clientId = json.path("clientId").asText(null);
return clientId != null ?
Mono.just(String.format("%s/%s", ipAddress, clientId) :
Mono.empty();
});
}
}
This works great to read the body and produce the desired key. However we quickly discovered that doing this consumes the body from the DataBuffer contained within the ServerHttpRequest. This seems to leave Spring Cloud Gateway unable to send the request to the downstream auth service.
Given the interface of this class, I don't think I can mutate the exchange instance to return the contents to the buffer.
How can I safely parse the body here?