Spring Boot 在 ServerOAuth2AuthorizedClientExchangeFilterFunction 中向 WebClient 请求添加附加属性

2024-04-24

我正在尝试实现 client_credentials 授予以在我的 Spring Boot 资源服务器中获取令牌。 我在用Auth0作为授权服务器。他们似乎需要在请求正文中添加一个名为“audience”的额外参数。

我尝试通过邮递员提出请求并且它有效。我现在正尝试在 Spring 中重现它。这是工作邮递员的请求

curl -X POST \
  https://XXX.auth0.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials&audience=https%3A%2F%2Fxxxxx.auth0.com%2Fapi%2Fv2%2F&client_id=SOME_CLIENT_ID&client_secret=SOME_CLIENT_SECRET'

我面临的问题是我无法将缺少的受众参数添加到令牌请求中。

我在 application.yml 中定义了一个配置

client:
    provider:
      auth0:
        issuer-uri: https://XXXX.auth0.com//
    registration:
      auth0-client:
        provider: auth0
        client-id: Client
        client-secret: Secret
        authorization_grant_type: client_credentials
      auth0:
        client-id: Client
        client-secret: Secret

我的网络客户端过滤器是这样配置的。

@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
                    ServerOAuth2AuthorizedClientRepository authorizedClients) {
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            clientRegistrations, authorizedClients);
    oauth2.setDefaultClientRegistrationId("auth0");
    return WebClient.builder()
            .filter(oauth2)
            .build();
}

我正在注入实例并尝试发出请求以通过电子邮件获取用户

 return this.webClient.get()
            .uri(this.usersUrl + "/api/v2/users-by-email?email={email}", email)
            .attributes(auth0ClientCredentials())
            .retrieve()
            .bodyToMono(User.class);

按照我的理解,过滤器拦截此 userByEmail 请求,并在执行之前尝试执行 /oauth/token 请求以获取 JWT Bearer 令牌,它可以将其附加到第一个请求并执行它。

有没有办法向过滤器添加参数?由于它是反应性的,因此很难逐步完成它并弄清楚参数到底附加在哪里,而且在这方面我还很陌生。甚至一些指向何处查找的指示也会有所帮助。


我遇到了同样的问题,访问令牌响应和请求不遵循 oAuth2 标准。这是我的 Spring Boot 版本的代码(它在 kotlin 中,但对于 Java 开发人员来说也应该可以理解)2.3.6.RELEASE。 梯度依赖:

implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}"))
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")

添加它们后,您必须首先创建自定义令牌请求/响应客户端,它将实现ReactiveOAuth2AccessTokenResponseClient界面:

class CustomTokenResponseClient : ReactiveOAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {

    private val webClient = WebClient.builder().build()

    override fun getTokenResponse(
            authorizationGrantRequest: OAuth2ClientCredentialsGrantRequest
    ): Mono<OAuth2AccessTokenResponse> =
            webClient.post()
                    .uri(authorizationGrantRequest.clientRegistration.providerDetails.tokenUri)
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .bodyValue(CustomTokenRequest(
                            clientId = authorizationGrantRequest.clientRegistration.clientId,
                            clientSecret = authorizationGrantRequest.clientRegistration.clientSecret
                    ))
                    .exchange()
                    .flatMap { it.bodyToMono<NotStandardTokenResponse>() }
                    .map { it.toOAuth2AccessTokenResponse() }


    private fun NotStandardTokenResponse.toOAuth2AccessTokenResponse() = OAuth2AccessTokenResponse
            .withToken(this.accessToken)
            .refreshToken(this.refreshToken)
            .expiresIn(convertExpirationDateToDuration(this.data.expires).toSeconds())
            .tokenType(OAuth2AccessToken.TokenType.BEARER)
            .build()

}

正如您在上面所看到的,在此类中,您可以根据您的特定需求调整令牌请求/响应处理。

Note: authorizationGrantRequest里面的参数getTokenResponse方法。 Spring 在这里传递来自应用程序属性的数据,因此在定义它们时请遵循标准,例如它们可能看起来像这样:

spring:
  security:
    oauth2:
      client:
        registration:
          name-for-oauth-integration:
            authorization-grant-type: client_credentials
            client-id: id
            client-secret: secret
        provider:
          name-for-oauth-integration:
            token-uri: https://oauth.com/token

最后一步是使用您的CustomTokenResponseClient在 oAuth2 配置中,它可能如下所示:

@Configuration
class CustomOAuth2Configuration {

    @Bean
    fun customOAuth2WebWebClient(clientRegistrations: ReactiveClientRegistrationRepository): WebClient {
        val clientRegistryRepo = InMemoryReactiveClientRegistrationRepository(
                clientRegistrations.findByRegistrationId("name-for-oauth-integration").block()
        )
        val clientService = InMemoryReactiveOAuth2AuthorizedClientService(clientRegistryRepo)

        val authorizedClientManager =
                AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistryRepo, clientService)
        val authorizedClientProvider = ClientCredentialsReactiveOAuth2AuthorizedClientProvider()
        authorizedClientProvider.setAccessTokenResponseClient(CustomTokenResponseClient())
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)

        val oauthFilter = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
        oauthFilter.setDefaultClientRegistrationId("name-for-oauth-integration")

        return WebClient.builder()
                .filter(oauthFilter)
                .build()
    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot 在 ServerOAuth2AuthorizedClientExchangeFilterFunction 中向 WebClient 请求添加附加属性 的相关文章

随机推荐