所有请求的spring webclient和共享客户端凭据令牌

20jt8wwn  于 2021-07-13  发布在  Java
关注(0)|答案(1)|浏览(493)

我尝试使用springwebclient和springsecurityoauth2客户端在两个应用程序之间进行通信。我需要使用oauth2客户端凭据授予类型,并对这些应用程序之间的所有请求使用相同的凭据和相同的令牌。在oauth2术语中,资源所有者是应用程序a本身,而资源服务器是应用程序b(它是key斗篷管理api)。我使用application.yaml和servlet环境中的spring引导自动配置。所以我就这样实现了:

WebClient buildWebClient(ClientRegistrationRepository clientRegistrationRepository,
    OAuth2AuthorizedClientRepository authorizedClientRepository, String clientName) {
  final ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
      clientRegistrationRepository, authorizedClientRepository);
  oauth2Client.setDefaultClientRegistrationId(clientName);

  return WebClient.builder()
      .apply(oauth2Client.oauth2Configuration())
      .build();
}

我发现我有一个问题,并且无效的令牌(我使用keydepot,如果我的keydepot重新启动,那么所有旧的令牌都是无效的)永远不会被删除(您可以在问题#9477中看到),所以我开始在中调试整个授权过程 ServletOAuth2AuthorizedClientExchangeFilterFunction . 我发现令牌是按应用程序a的每个用户保存的。这意味着应用程序a的每个用户都有自己的令牌来授权应用程序b。但这不是我想要的行为,我只想在应用程序a中使用一个令牌来消耗来自应用程序b的资源。
我认为我找到了两个解决方案,但它们都不是最优的。
解决方案1:在之后添加另一个默认请求 ServletOAuth2AuthorizedClientExchangeFilterFunction 它取代了用户 Authentication 应用程序在属性中 Authentication . 问题是它依赖于 ServletOAuth2AuthorizedClientExchangeFilterFunction 使用私有属性 AUTHENTICATION_ATTR_NAME = Authentication.class.getName(); .

return WebClient.builder()
      .apply(oauth2Client.oauth2Configuration())
      .defaultRequest(spec -> spec.attributes(attr -> 
           attr.put(AUTHENTICATION_ATTR_NAME, new CustomApplicaitonAuthentication())
        )
      .build();

解决方案2:使用 OAuth2AuthorizedClientRepository 而不是默认值 AuthenticatedPrincipalOAuth2AuthorizedClientRepository (由于删除无效令牌的问题,我不得不这样做)我忽略了用户的 Authentication 我使用自定义应用程序 Authentication .

@Override
public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(String clientRegistrationId, Authentication principal,
                                                                        HttpServletRequest request) {
  return this.authorizedClientService.loadAuthorizedClient(clientRegistrationId, new CustomApplicaitonAuthentication());
}

@Override
public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal,
                                    HttpServletRequest request, HttpServletResponse response) {
  this.authorizedClientService.saveAuthorizedClient(authorizedClient, new CustomApplicaitonAuthentication());
}

但我认为我的两个解决方案都不是最优的。有没有其他方法可以更直接地做到这一点?

ccgok5k5

ccgok5k51#

我找到了解决方案,因为我需要在没有servlet请求(消息传递、调度程序等)的情况下运行它。因此我需要更新它并使用 AuthorizedClientServiceOAuth2AuthorizedClientManager 而不是默认值 DefaultOAuth2AuthorizedClientManager . 然后我意识到它做的和我需要的一样。

@Bean
 WebClient buildWebClient(
      OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager,
      OAuth2AuthorizationFailureHandler oAuth2AuthorizationFailureHandler,
      String clientName) {

    final ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
        oAuth2AuthorizedClientManager);
    oauth2Client.setDefaultClientRegistrationId(clientName);
    oauth2Client.setAuthorizationFailureHandler(oAuth2AuthorizationFailureHandler);

    return WebClient.builder()
        .apply(oauth2Client.oauth2Configuration())
        .build();
  }

  @Bean
  public OAuth2AuthorizedClientManager authorizedClientManager
      (ClientRegistrationRepository clients, OAuth2AuthorizedClientService service, OAuth2AuthorizationFailureHandler authorizationFailureHandler) {
    AuthorizedClientServiceOAuth2AuthorizedClientManager manager =
        new AuthorizedClientServiceOAuth2AuthorizedClientManager(clients, service);
    manager.setAuthorizationFailureHandler(authorizationFailureHandler);
    return manager;
  }

  @Bean
  public OAuth2AuthorizationFailureHandler resourceServerAuthorizationFailureHandler(
      OAuth2AuthorizedClientService authorizedClientService) {
    return new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
        (clientRegistrationId, principal, attributes) -> 
          authorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName()));
  }

我们必须增加一个自定义 OAuth2AuthorizationFailureHandler 因为如果你不使用这个构造函数 ServletOAuth2AuthorizedClientExchangeFilterFunction(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) 你用一个自定义的 OAuth2AuthorizedClientManager 然后它没有配置,您必须手动执行。

相关问题