We are using Spring Cloud Gateway with a GlobalFilter to handle token injection to the request. Here is the code for the filter:
@Override
public Mono<Void> filter(final ServerWebExchange exchange, final GatewayFilterChain chain) {
log.info("We received a request");
exchange.getRequest().mutate()
.headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));
return chain.filter(exchange);
}
The tokenService.getToken()
-method returns either a token from cache or a new one from the backend if none exists in the cache, yet. But it may come to the point that the token will be invalidated in the backend. If a request is then made with the token again, the backend responds with a 401. In this case we want to intercept the response, invalidate the cache, request a new token from the backend (which is cached again afterwards) and resend the request with the new token. Additionally a header is set indicating that the request has been retried for avoiding an infinite loop.
This should happen transparently for the client.
Following a short illustration about what should be the desired data flow:
What I've already tried so far:
@Override
public Mono<Void> filter(final ServerWebExchange exchange, final GatewayFilterChain chain) {
log.info("We received a request");
exchange.getRequest().mutate()
.headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
final ServerHttpResponse response = exchange.getResponse();
if (response.getStatusCode().is4xxClientError()) {
log.error("We got a 4xx");
if (!exchange.getRequest().getHeaders().containsKey("X-retries")) {
log.info("Trying to resend request");
exchange.getRequest().mutate()
.headers(h -> h.add("X-retries", "1"));
tokenService.evictCache();
exchange.getRequest().mutate()
.headers(h -> h.remove("Authorization"))
.headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));
chain.filter(exchange);
} else {
log.info("Retry failed");
}
}
}));
}
But I cannot see the second request in the backend log.
How can I send the modified request again to the backend?
I suppose the error is in the part of code:
It does not change the existed
exchange
, it creates a new one. So, you need save link to mutated object, like:After that the
newExchange
must be used in your code