jlfeld1
jlfeld1

Reputation: 1

How do I get a spring cloud GatewayFilter to trigger a fallback route with a CircuitBreaker?

I have an oauth2 token fetching gateway filter that I need to wire a circuit breaker in. If I can't connect to the provider or authentication fails, I need to use the fallback route.

My filter is below:


import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
import org.springframework.stereotype.Component;

@Component
public class Oauth2GatewayFilterFactory extends AbstractGatewayFilterFactory<Oauth2GatewayFilterFactory.Config> {

    private final ReactiveOAuth2AuthorizedClientManager authorizedClientManager;

    public Oauth2GatewayFilterFactory(
            ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
        super(Config.class);
        this.authorizedClientManager = authorizedClientManager;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            final var clientRegistrationId = config.getClientRegistrationId();
            final var oauth2Request = OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistrationId)
                    .principal("N/A")
                    .build();
            return authorizedClientManager.authorize(oauth2Request)
                    .map(authorizedClient -> exchange.mutate()
                            .request(r -> r.headers(
                                    headers -> headers.set(HttpHeaders.AUTHORIZATION,
                                            "Bearer " + authorizedClient.getAccessToken().getTokenValue())))
                            .build())
                    .defaultIfEmpty(exchange)
                    .flatMap(chain::filter);
        };
    }

    public static class Config {

        private String clientRegistrationId;

        public String getClientRegistrationId() {
            return clientRegistrationId;
        }

        public void setClientRegistrationId(String clientRegistrationId) {
            this.clientRegistrationId = clientRegistrationId;
        }

    }

}

I've attempted wiring the circuit breaker into the filter factory and then doing a transformDeferred

return authorizedClientManager.authorize(oauth2Request)
        .transformDeferred(CircuitBreakerOperator.of(circuitBreaker))
        .map(authorizedClient -> {

but this doesn't help me.

How do I wire in the circuit breaker?

Upvotes: 0

Views: 35

Answers (1)

jlfeld1
jlfeld1

Reputation: 1

I got around it without the circuit breaker by using a pattern like this:

return authorizedClientManager.authorize(oauth2Request)
        .map(authorizedClient -> exchange.mutate()
                .request(r -> r.headers(
                        headers -> headers.set(HttpHeaders.AUTHORIZATION,
                                "Bearer " + authorizedClient.getAccessToken().getTokenValue())))
                .build())
        .onErrorResume(e -> Mono.empty())  // Ignore the error
        .defaultIfEmpty(exchange)  // Then continue if an occurred, allowing routed request to fail with a 401
        .flatMap(chain::filter);

Upvotes: 0

Related Questions