java—在SpringSecurity5中,为什么authorizedclientmanager和exchangefilterfunction都需要authorizationfailurehandler?

2skhul33  于 2021-06-26  发布在  Java
关注(0)|答案(0)|浏览(359)

我在spring中实现了一个资源服务器,需要配置一个webclient,以便从其他api访问下游数据。该webclient需要协商oauth2流的客户端凭据。相当典型的东西。我感到困惑的是:
为此配置webclient时,我首先定义一个适当的 ReactiveOAuth2AuthorizedClientManager . 然后我定义一个合适的 ExchangeFilterFunction ,用我的客户机管理器初始化它。根据spring的文档(并通过查看源代码进行确认),在以这种方式初始化filter函数时,我仍然需要显式地设置 authorizationFailureHandler 即使客户经理也有同样的想法 authorizationFailureHandler 自动配置。
我是不是遗漏了为什么要这么做?也许这是 Spring 保安的问题。
这是我的密码:

@Bean
public WebClient webClientForSomeDownstreamAPI(
                       ReactiveClientRegistrationRepository clientRegistrationRepository,
                       ReactiveOAuth2AuthorizedClientService authorizedClientService) {
    AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
            new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
                    clientRegistrationRepository,
                    authorizedClientService);

    authorizedClientManager.setAuthorizedClientProvider(
            ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
                .clientCredentials()
                .build());

    ReactiveOAuth2AuthorizationFailureHandler authorizationFailureHandler = 
            new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
                (clientRegistrationId, principal, attributes) -> 
                        authorizedClientService.removeAuthorizedClient(
                        clientRegistrationId, principal.getName()));

    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
            new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);

    //for some reason the filter function and the client manager both need a failure handler
    oauth.setAuthorizationFailureHandler(authorizationFailureHandler);
    oauth.setDefaultClientRegistrationId("redacted");

    return WebClient.builder()
            .filter(oauth)
            .clientConnector(createClientConnectorWithLogging())
            .baseUrl("redacted")
            .build();
}

Spring的 AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager (天哪,真是满嘴废话)使用对传入的文件的引用自动配置故障处理程序 authorizedClientService 如下面的代码片段所示(取自源代码)。

public AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ReactiveOAuth2AuthorizedClientService authorizedClientService) {
        Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
        Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
        this.clientRegistrationRepository = clientRegistrationRepository;
        this.authorizedClientService = authorizedClientService;
        this.authorizationSuccessHandler = (authorizedClient, principal, attributes) -> authorizedClientService
                .saveAuthorizedClient(authorizedClient, principal);
        this.authorizationFailureHandler = new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
                (clientRegistrationId, principal, attributes) -> this.authorizedClientService
                        .removeAuthorizedClient(clientRegistrationId, principal.getName()));
    }

但是 ServerOAuth2AuthorizedClientExchangeFilterFunction 我使用的构造函数(将客户机管理器作为参数)需要我随后显式地设置失败处理程序。请参见javadoc中的以下片段:

/**
     * When this constructor is used, authentication (HTTP 401) and authorization (HTTP
     * 403) failures returned from a OAuth 2.0 Resource Server will <em>NOT</em> be
     * forwarded to a {@link ReactiveOAuth2AuthorizationFailureHandler}. Therefore, future
     * requests to the Resource Server will most likely use the same (most likely invalid)
     * token, resulting in the same errors returned from the Resource Server. It is
     * recommended to configure a
     * {@link RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler} via
     * {@link #setAuthorizationFailureHandler(ReactiveOAuth2AuthorizationFailureHandler)}
     * so that authentication and authorization failures returned from a Resource Server
     * will result in removing the authorized client, so that a new token is retrieved for
     * future requests.

* /

有趣的是另一个filter函数构造函数确实创建了一个 authorizationFailureHandler 它几乎和客户经理自动创建的内容一样。请看这里:

public ServerOAuth2AuthorizedClientExchangeFilterFunction(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
        ReactiveOAuth2AuthorizationFailureHandler authorizationFailureHandler = new RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler(
                (clientRegistrationId, principal, attributes) -> authorizedClientRepository.removeAuthorizedClient(
                        clientRegistrationId, principal,
                        (ServerWebExchange) attributes.get(ServerWebExchange.class.getName())));
        this.authorizedClientManager = createDefaultAuthorizedClientManager(clientRegistrationRepository,
                authorizedClientRepository, authorizationFailureHandler);
        this.clientResponseHandler = new AuthorizationFailureForwarder(authorizationFailureHandler);
        this.defaultAuthorizedClientManager = true;
    }

我知道客户经理不会公开 authorizationFailureHandler 所以我调用的过滤器函数构造函数不能仅仅引用它。但这是怎么回事?让两个失败处理程序对同一个对象执行相同的操作是不对的 authorizedClientService 所以我肯定错过了什么。
我使用的是springboot2.4.1和springsecurity 5.4.2。

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题