Я был в той же ситуации, что и вы, и нашел решение. Прежде всего, чтобы увидеть это в действии, я создал репозиторий с демонстрационной реализацией всего, что объясняется ниже.
есть ли более «чистый» способ заменить используемый мной компонент WebClient на тот, который будет вызывать мою поддельную удаленную службу, не пытаясь сначала получить токен?
Я бы не стал заменять bean-компонент WebClient
в вашем тесте, а скорее заменил бы _ 2_ bean с имитацией. Чтобы это сработало, вам нужно немного изменить свой MyRemoteServiceClientOauth2Config
. Вместо использования устаревшего подхода с _ 4_, вы настраиваете его таким образом (это также больше соответствует задокументированная конфигурация в стеке сервлетов):
@Configuration
public class MyRemoteServiceClientOauth2Config {
@Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2ClientCredentialsFilter =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(reactiveOAuth2AuthorizedClientManager);
oauth2ClientCredentialsFilter.setDefaultClientRegistrationId("myRemoteService");
return WebClient.builder()
.filter(oauth2ClientCredentialsFilter)
.build();
}
@Bean
public ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager(ReactiveClientRegistrationRepository clientRegistrations,
ReactiveOAuth2AuthorizedClientService authorizedClients) {
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, authorizedClients);
authorizedClientManager.setAuthorizedClientProvider(
new ClientCredentialsReactiveOAuth2AuthorizedClientProvider());
return authorizedClientManager;
}
}
Затем вы можете создать имитацию ReactiveOAuth2AuthorizedClientManager
, которая всегда возвращает Mono
_ 8_ вот так:
@TestComponent
@Primary
public class AlwaysAuthorizedOAuth2AuthorizedClientManager implements ReactiveOAuth2AuthorizedClientManager {
@Value("${spring.security.oauth2.client.registration.myRemoteService.client-id}")
String clientId;
@Value("${spring.security.oauth2.client.registration.myRemoteService.client-secret}")
String clientSecret;
@Value("${spring.security.oauth2.client.provider.some-keycloak.token-uri}")
String tokenUri;
/**
* {@inheritDoc}
*
* @return
*/
@Override
public Mono<OAuth2AuthorizedClient> authorize(final OAuth2AuthorizeRequest authorizeRequest) {
return Mono.just(
new OAuth2AuthorizedClient(
ClientRegistration
.withRegistrationId("myRemoteService")
.clientId(clientId)
.clientSecret(clientSecret)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.tokenUri(tokenUri)
.build(),
"some-keycloak",
new OAuth2AccessToken(TokenType.BEARER,
"c29tZS10b2tlbg==",
Instant.now().minus(Duration.ofMinutes(1)),
Instant.now().plus(Duration.ofMinutes(4)))));
}
}
И, наконец, @Import
, что в вашем тесте:
@SpringBootTest
@Import(AlwaysAuthorizedOAuth2AuthorizedClientManager.class)
class YourIntegrationTestClass {
// here is your test code
}
Соответствующий src/test/resources/application.yml
выглядит так:
spring:
security:
oauth2:
client:
registration:
myRemoteService:
authorization-grant-type: client_credentials
client-id: test-client
client-secret: 6b30087f-65e2-4d89-a69e-08cb3c9f34d2 # bogus
provider: some-keycloak
provider:
some-keycloak:
token-uri: https://some.bogus/token/uri
Альтернатива
Вы также можете просто использовать тот же mockserver
, который вы уже используете, для имитации своего REST-ресурса, а также для имитации сервера авторизации и ответа на запрос токена. Чтобы это работало, вы должны настроить mockserver
как token-uri
в src/test/resources/application.yml
или что-то еще, что вы используете для предоставления свойств вашему тесту соответственно.
Примечания
Прямое введение WebClient
Рекомендуемый способ добавить WebClient
в ваши beans - ввести WebClient.Builder
, который получит предварительно настроен с помощью Spring Boot. Это также гарантирует, что WebClient
в вашем тесте настроен точно так же, как и в производственной среде. Вы можете объявить WebClientCustomizer
beans в настройте этот конструктор дальше. Именно так это реализовано в моем репозитории витрин, упомянутом выше.
Переопределение / приоритезация бина с @Primary
на @Bean
внутри @Configuration
или @TestConfiguration
Я тоже пробовал это и обнаружил, что это не всегда работает так, как можно было бы ожидать, вероятно, из-за порядка, в котором Spring загружает и создает определения bean-компонентов. Например, макет ReactiveOAuth2AuthorizedClientManager
используется только в том случае, если @TestConfiguration
является классом static nested
внутри тестового класса, но не если он @Import
ed. Наличие static nested @TestConfiguration
на интерфейсе и реализация этого с помощью тестового класса также не работает. Итак, чтобы не использовать этот класс static nested
в каждом интеграционном тесте, в котором он мне нужен, я предпочитаю подход @TestComponent
, представленный здесь.
Другие типы грантов OAuth 2.0
Я тестировал свой подход только для Client Credentials
типа гранта, но я думаю, что он также может быть адаптирован или расширен для других типов грантов.
person
clocken
schedule
10.04.2021