Мне нужно запросить новый токен авторизации с использованием гранта учетных данных клиента (OAuth2) от KeyCloak после сбоя GET-запроса с WebClient из-за 401 Unauthorized WebClientResponseException
или исключения тайм-аута. Поэтому я использую метод Mono.retryWhen(...)
. Самый популярный ответ на SO гласит здесь , что его можно решить с помощью фильтра, который использует TokenProvider
. И что в будущем выпуске Spring-Security будет более элегантное решение. К сожалению, я не смог заставить этот код работать, и не нашел элегантного решения.
WebClientConfig-Bean:
@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations, ReactiveOAuth2AuthorizedClientService authorizedClientService) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, authorizedClientService));
oauth.setDefaultClientRegistrationId("keycloak");
return WebClient.builder()
.filter(oauth)
.build();
}
Реализация WebClient
public <T> Mono<T> callServiceOAuth2(String uri, Class<T> type, String logPrefix) {
return webClient.get()
.uri(uri)
.retrieve()
.bodyToMono(type)
.publishOn(Schedulers.boundedElastic())
.doOnRequest(s -> LOGGER.info("{} Send request on URL: {}", logPrefix, uri))
.retryWhen(Retry.backoff(5, Duration.ofSeconds(5))
.scheduler(Schedulers.boundedElastic())
.doAfterRetry( retry -> LOGGER.error("{} Retry: {} on {}, Error Message: {}",logPrefix, retry.totalRetries()+1, uri, retry.failure())))
.elapsed(Schedulers.boundedElastic())
.doOnNext(tuple -> LOGGER.info("{} Service response time: {}s", logPrefix, Duration.ofMillis(tuple.getT1()).toSeconds()))
.map(Tuple2::getT2) // after outputting the measurement, return the data only
.onErrorResume(fallback -> {LOGGER.error("{} Retry Exceeded, Exception: {}", logPrefix, fallback.toString()); return Mono.empty();}) ;
}
POM зависимости
spring-boot-starter-parent: 2.2.6.RELEASE
spring-boot-starter-webflux: 2.2.6.RELEASE
spring-security-oauth2-client: 5.3.1.RELEASE
spring-security-config: 5.3.1.RELEASE
application.yml
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: 'testclient_xyz'
client-secret: 'abc'
authorizationGrantType: client_credentials
provider:
keycloak:
token-uri: https://abc.de/auth/realms/my_realm/protocol/openid-connect/token