Веб-клиент весенней загрузки с OAuth2 и используйте InsecureTrustManagerFactory

#spring-boot #spring-oauth2 #spring-webclient

Вопрос:

Я успешно внедрил WebClient с помощью OAuth2. Сталкиваюсь с проблемой с OAuth2, когда на сервере аутентификации (Keycloak) используется протокол SSL (https). Хотя я передаю InsecureTrustManagerFactory при определении WebClient, этот OAuth вызывается до завершения компоновщика, как указано в фильтре, он использует реализацию WebClient по умолчанию и выдает ошибку сертификации.

Есть ли способ настроить клиент OAuth2 также для использования InsecureTrustManagerFactory?

pom.xml часть

 <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
 

Конфигурация Бобов

 @Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
        final ReactiveClientRegistrationRepository clientRegistrationRepository,
        final ReactiveOAuth2AuthorizedClientService authorizedClientService) {
    logger.info("ReactiveOAuth2AuthorizedClientManager Bean Method");
    ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
            .builder().password().build();

    AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
            clientRegistrationRepository, authorizedClientService);

    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    authorizedClientManager.setContextAttributesMapper(oAuth2AuthorizeRequest -> Mono
            .just(Map.of(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, System.getProperty("user"),
                    OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, System.getProperty("pass"))));

    return authorizedClientManager;
}

/**
 * The Oauth2 based WebClient bean for the web service
 * 
 * @throws SSLException
 */
@Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) throws SSLException {

    String registrationId = "bael";

    SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();

    SslProvider sslProvider = SslProvider.builder().sslContext(sslContext).build();

    HttpClient httpClient = HttpClient.create().secure(sslProvider)
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000).responseTimeout(Duration.ofMillis(5000))
            .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))
                    .addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)));

    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            authorizedClientManager);
    oauth.setDefaultClientRegistrationId(registrationId);
    logger.info("WebClient Bean Method");
    return WebClient.builder()
            // base path of the client, this way we need to set the complete url again
            .baseUrl("BASE_URL")
            .clientConnector(new ReactorClientHttpConnector(httpClient))
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).filter(logRequest())
            .filter(oauth).filter(logResponse()).build();
}
 

Ответ №1:

Поэтому вам также придется создать новый веб-клиент для OAuth2. В вашем определении authorizedClientManager добавьте несколько строк(лучше иметь компонент HttpClient, чтобы вы не определяли его все время).

 SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();
SslProvider sslProvider = SslProvider.builder().sslContext(sslContext).build();
HttpClient httpClient = HttpClient.create().secure(sslProvider)
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000).responseTimeout(Duration.ofMillis(5000))
            .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))
                    .addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)));
WebClient webClient = WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
WebClientReactiveClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient =
                new WebClientReactiveClientCredentialsTokenResponseClient();
        clientCredentialsTokenResponseClient.setWebClient(webClient);
 

и добавьте в свой авторизованный поставщик Clientprovider ->

 ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
            .builder().password(builder -> builder.accessTokenResponseClient(clientCredentialsTokenResponseClient)).build();