如何将自定义 OAuth2AuthorizationFailureHandler 添加到 DefaultOAuth2AuthorizedClientManager?

How do I add a custom OAuth2AuthorizationFailureHandler to the DefaultOAuth2AuthorizedClientManager?

我正在使用 spring-security,我正在尝试将我自己的 OAuth2AuthorizationFailureHandler 添加到 DefaultOAuth2AuthorizedClientManager,但我找不到这样做的方法。它似乎不是 Bean;它看起来像是在 OAuth2ClientConfiguration.OAuth2ClientWebMvcSecurityConfiguration.addArgumentResolvers().

中实例化的

这个 github 问题看起来应该让我能够做到这一点,但我仍然无法弄清楚如何:https://github.com/spring-projects/spring-security/issues/7583

我阅读了 https://github.com/spring-projects/spring-security/commit/2dd40c7de5de72b8f18a51c490d640619c5a6301 中添加的文档,但我仍然感到困惑。

我想添加失败处理程序的原因是我想处理刷新令牌过期时 RefreshTokenOAuth2AuthorizedClientProvider.authorize() 抛出的 OAuth2AuthorizationException。具体来说,当刷新令牌过期时,我想用 HTTP 403 而不是 HTTP 500 进行响应。

我想出了如何自定义 DefaultOAuth2AuthorizedClientManager 的失败处理程序,但它实际上并没有实现我的最终目标,即在尝试使用过期的刷新令牌检索来自身份验证服务器的新访问令牌。

要处理 OAuth2AuthorizationException,请创建一个带有 @ExceptionHandler(OAuth2AuthorizationException.class) 注释方法的 @ControllerAdvice class,它可以执行您想要的任何操作。这是我所做的:

@ControllerAdvice
public class GlobalControllerAdvice {

  /**
   * spring-security-oauth2 automatically refreshes the access token while resolving
   * \@RegisteredOAuth2AuthorizedClient-annotated parameters to @RequestMapping methods.  When it
   * fails to refresh an OAuth2 access token because the refresh token is expired,
   * RefreshTokenOAuth2AuthorizedClientProvider.authorize() throws an OAuth2AuthorizationException.
   * If we didn't handle it here, we'd respond with a HTTP 500, and that's no good.  Instead, we
   * respond with HTTP 403 so that the UI can log itself out.
   */
  @ExceptionHandler(OAuth2AuthorizationException.class)
  ResponseEntity<?> handleHttpStatusCodeException(OAuth2AuthorizationException e) {
    return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
  }

}

如果出于某种原因你想自定义 DefaultOAuth2AuthorizedClientManager 失败处理程序,您可能需要创建一个全新的 OAuth2AuthorizedClientArgumentResolver bean(如下所示)并通过 WebMvcConfigurer(以下未显示)注册它:

@Bean
@Order(0)
public OAuth2AuthorizedClientArgumentResolver oAuth2AuthorizedClientArgumentResolver(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
  final OAuth2AuthorizedClientArgumentResolver oAuth2AuthorizedClientArgumentResolver = new OAuth2AuthorizedClientArgumentResolver(oAuth2AuthorizedClientManager);
  return oAuth2AuthorizedClientArgumentResolver;
}

@Bean
public OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) {
  final DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
      clientRegistrationRepository, authorizedClientRepository);

  authorizedClientManager.setAuthorizationFailureHandler(new OAuth2AuthorizationFailureHandler() {
    @Override
    public void onAuthorizationFailure(OAuth2AuthorizationException e,
        Authentication authentication, Map<String, Object> map) {
      // Handle auth failure here
    }
  });

  return authorizedClientManager;
}