Spring Security 5 在 Application Runner 中调用 OAuth2 Secured API 导致 IllegalArgumentException [英] Spring Security 5 Calling OAuth2 Secured API in Application Runner results in IllegalArgumentException

查看:17
本文介绍了Spring Security 5 在 Application Runner 中调用 OAuth2 Secured API 导致 IllegalArgumentException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下代码,是否可以在应用程序运行器中调用客户端凭据安全 API?

Given the following code, is it possible to call a Client Credentials secured API in an application runner?

@Bean
public ApplicationRunner test(
    WebClient.Builder builder,
    ClientRegistrationRepository clientRegistrationRepo, 
    OAuth2AuthorizedClientRepository authorizedClient) {
        return args -> {
            try {
                var oauth2 =
                    new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                        clientRegistrationRepo,
                        authorizedClient);
                oauth2.setDefaultClientRegistrationId("test");
                var response = builder
                    .apply(oauth2.oauth2Configuration())
                    .build()
                    .get()
                    .uri("test")
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
                log.info("Response - {}", response);
            } catch (Exception e) {
                log.error("Failed to call test.", e);
            }
        };
    }

代码失败的原因是,

java.lang.IllegalArgumentException: request cannot be null

全栈,

java.lang.IllegalArgumentException: request cannot be null
    at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository.loadAuthorizedClient(HttpSessionOAuth2AuthorizedClientRepository.java:47) ~[spring-security-oauth2-client-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.populateDefaultOAuth2AuthorizedClient(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:364) ~[spring-security-oauth2-client-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.lambda$null$2(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:209) ~[spring-security-oauth2-client-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.attributes(DefaultWebClient.java:234) ~[spring-webflux-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.attributes(DefaultWebClient.java:153) ~[spring-webflux-5.1.5.RELEASE.jar:5.1.5.RELEASE]

失败的方法看起来像,

public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(
    String clientRegistrationId,  Authentication principal, HttpServletRequest request){

    Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty");
    Assert.notNull(request, "request cannot be null");
    return (OAuth2AuthorizedClient)this
        .getAuthorizedClients(request)
        .get(clientRegistrationId);
}

这是有道理的,因为没有 HttpServletRequest 供它使用,它在应用程序启动时被调用.

Which makes sense as there is not HttpServletRequest for it to use, its being called on start-up of the application.

除了创建我自己的无操作 OAuth2AuthorizedClientRepository 之外,还有其他解决方法吗?

Is there any workarounds other than make my own no-op OAuth2AuthorizedClientRepository?

//编辑,

这不是一个完全反应式的堆栈.它是一个 Spring Web 堆栈,其中使用了 WebClient.

This is not a fully reactive stack. It is a Spring Web stack with the WebClient being used with in it.

我很清楚 ServerOAuth2AuthorizedClientExchangeFilterFunction 适用于完全反应式堆栈并需要 ReactiveClientRegistrationRepositoryReactiveOauth2AuthorizedClient 由于这个原因不可用处于构建在 Servlet 堆栈之上的应用程序中,而不是反应性的.

I am well aware of the ServerOAuth2AuthorizedClientExchangeFilterFunction which applies to a fully reactive stack and requires ReactiveClientRegistrationRepository and ReactiveOauth2AuthorizedClient which are not available due to this being in an application built on top of Servlet stack, not reactive.

推荐答案

由于我也偶然发现了这个问题,所以我将详细介绍 Darren Forsythe 的 更新答案,让其他人更容易找到:

Since I also stumbled across this problem I'll elaborate a bit on Darren Forsythe's updated answer to make it easier for others to find:

OP 提交的问题导致 OAuth2AuthorizedClientManager 的实现能够

The issue submitted by the OP resulted in an implementation of OAuth2AuthorizedClientManager that is capable of

在 HttpServletRequest 上下文之外操作,例如在计划/后台线程和/或服务层中

operating outside of a HttpServletRequest context, e.g. in a scheduled/background thread and/or in the service-tier

(来自官方文档)

所述实现,AuthorizedClientServiceOAuth2AuthorizedClientManager,被传递给ServletOAuth2AuthorizedClientExchangeFilterFunction 以替换默认的.

Said implementation, the AuthorizedClientServiceOAuth2AuthorizedClientManager, is passed to the ServletOAuth2AuthorizedClientExchangeFilterFunction to replace the default one.

在我的示例中,这看起来像这样:

In my example this looks something like this:

@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientService clientService)
{

    OAuth2AuthorizedClientProvider authorizedClientProvider = 
        OAuth2AuthorizedClientProviderBuilder.builder()
            .clientCredentials()
            .build();

    AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = 
        new AuthorizedClientServiceOAuth2AuthorizedClientManager(
            clientRegistrationRepository, clientService);
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    return authorizedClientManager;
}

@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager)
{
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
        new ServletOAuth2AuthorizedClientExchangeFilterFunction(
            authorizedClientManager);
    oauth2.setDefaultClientRegistrationId("keycloak");
    return WebClient.builder().apply(oauth2.oauth2Configuration()).build();
}

这篇关于Spring Security 5 在 Application Runner 中调用 OAuth2 Secured API 导致 IllegalArgumentException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆