是否支持 Spring Boot WebClient OAuth2 client_credentials?

Posted

技术标签:

【中文标题】是否支持 Spring Boot WebClient OAuth2 client_credentials?【英文标题】:Is Spring Boot WebClient OAuth2 client_credentials supported? 【发布时间】:2019-09-17 13:15:54 【问题描述】:

我正在尝试创建一个 Spring Boot REST 应用程序,该应用程序必须对另一个受 OAuth2 保护的 Spring Boot 应用程序(具有授权类型 client_credentials)进行远程 REST 调用。

第一个应用程序正在使用 Reactive WebClient 来调用第二个 OAuth2 REST 应用程序。

我已经用 grant_type "client_credentials" 配置了 WebClient(参见下面的代码)

public WebClient messageWebClient(
        ClientRegistrationRepository clientRegistrations,
        OAuth2AuthorizedClientRepository authorizedClients,
        ClientHttpConnector clientHttpConnector
) 

    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);

    oauth.setDefaultClientRegistrationId("message");

    return WebClient.builder()
            .baseUrl(MESSAGE_BASE_URL)
            .clientConnector(clientHttpConnector)
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
            .filter(oauth)
            .filter(logRequest())
            .build();


@Bean
public ClientRegistrationRepository  clientRegistrations() 
    ClientRegistration clientRegistration = ClientRegistration
            .withRegistrationId("message")
            .clientId("client")
            .clientSecret("secret")
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .tokenUri("http://localhost:8081/oauth/token")
            .build();

    return new InMemoryClientRegistrationRepository(clientRegistration);

但是每次我对第一个应用程序进行 Postman 调用时,我都会遇到以下异常:

“IllegalArgumentException:无效的授权授予类型 (client_credentials) 用于 Id 的客户端注册:...”来自 DefaultOAuth2AuthorizationRequestResolver

WebClient 真的支持“client_credentials”吗...还是我遗漏了什么?

问候

第一个应用程序代码: https://github.com/fdlessard/SpringBootOauth2WebClient

第二个应用程序代码: https://github.com/fdlessard/SpringBootOAuth2Message

SpringBoot 2.1.4 版

spring-security-oauth2-client: 5.1.5.RELEASE

【问题讨论】:

在文档中使用的是.apply(oauth2.oauth2Configuration()) 而不是.filter(oauth)。为什么你是另一种方式? 我尝试了 .apply .apply(oauth2.oauth2Configuration()) 而不是 .filter(oauth) 并且它开始工作....在调试中部分是两次中的 1 次...模式。取得了一些进展。谢谢 你能添加完整的堆栈吗?看起来它应该是成功的,我不认为它的失败是因为客户端代码。 【参考方案1】:

您必须使用.apply(oauth.oauth2Configuration()) 而不是.filter(oauth),请参阅ServletOAuth2AuthorizedClientExchangeFilterFunction

通过将令牌作为不记名令牌包含在内,提供使用OAuth2AuthorizedClient 发出 OAuth2 请求的简单机制。它还提供了查找OAuth2AuthorizedClient 的机制。此类旨在用于 servlet 环境。示例用法:

OAuth2AuthorizedClientExchangeFilterFunction oauth2 = new OAuth2AuthorizedClientExchangeFilterFunction(authorizedClientService);
WebClient webClient = WebClient.builder()
    .apply(oauth2.oauth2Configuration())
    .build();
Mono response = webClient
    .get()
    .uri(uri)
    .attributes(oauth2AuthorizedClient(authorizedClient))
    // ...
    .retrieve()
    .bodyToMono(String.class);

和Spring Security Reference:

13.1 WebClient OAuth2 设置

第一步是确保正确设置 WebClient。在 servlet 环境中设置 WebClient 的示例如下:

@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrations,
        OAuth2AuthorizedClientRepository authorizedClients) 
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
    // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
    // oauth.setDefaultOAuth2AuthorizedClient(true);
    // (optional) set a default ClientRegistration.registrationId
    // oauth.setDefaultClientRegistrationId("client-registration-id");
    return WebClient.builder()
            .apply(oauth2.oauth2Configuration())
            .build();

【讨论】:

【参考方案2】:

好吧,我终于可以让我的代码工作了。

...是的,WebClient 确实支持带有 client_credential 的 OAuth2(部分好)。

为了解决我的问题我不得不禁用 oauth2 自动配置并创建自己的 WebSecurityConfigurerAdapter 实现。

我说“部分”的原因是因为 WebClient 的当前版本的 spring security (5.1.x) 在令牌过期后不会要求新的令牌(对于客户端凭据)。仅在 5.2.0.M2 或 (M1) 版本中,它会在令牌过期时请求新令牌。

谢谢你:)

【讨论】:

想分享一下你是怎么做到的?

以上是关于是否支持 Spring Boot WebClient OAuth2 client_credentials?的主要内容,如果未能解决你的问题,请参考以下文章

是否支持 Spring Boot WebClient OAuth2 client_credentials?

Vaadin Flow 是不是支持 Spring-Boot Native

QueryDSL、spring-boot 和 Gradle

Spring Boot + Spring Data 多租户

Spring Boot 是不是支持 RDBMS DB 的主从配置

从 json 文件加载 spring-boot 属性