【问题标题】:How to customize the Authorization header of the OAuth2 token request如何自定义 OAuth2 令牌请求的 Authorization 标头
【发布时间】:2021-09-20 05:27:00
【问题描述】:

我正在使用 Spring Security 5.5 执行访问令牌请求,最近升级到 5.5.1,现在我的客户端密码被我的 OAuth 2.0 提供者拒绝。这是由a bug fix 根据RFC 6749 Section 2.3.1 对客户端凭据进行 URL 编码引起的。

由于我的 OAuth 2.0 提供程序不合规,我想恢复到 Spring Security 5.5.0 中的旧行为,并在没有 URL 编码的情况下发送我的客户端凭据。

reference documentation,如果我定义了OAuth2AuthorizedClientManager 类型的@Bean

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientRepository authorizedClientRepository) {
        // @formatter:off
        OAuth2AuthorizedClientProvider authorizedClientProvider =
            OAuth2AuthorizedClientProviderBuilder.builder()
                .clientCredentials()
                .build();

        DefaultOAuth2AuthorizedClientManager authorizedClientManager =
            new DefaultOAuth2AuthorizedClientManager(
                clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
        // @formatter:on

        return authorizedClientManager;
    }

如何配置它以使用自定义转换器来设置凭据?

注意:this question 相关,但解决的是 Servlet 支持而不是 WebClient 的响应式支持。

【问题讨论】:

    标签: spring-security oauth-2.0


    【解决方案1】:

    假设你有以下配置:

    spring:
      security:
        oauth2:
          client:
            registration:
              test-client:
                provider: spring
                client-id: aladdin
                client-secret: "open sesame"
                authorization-grant-type: client_credentials
                redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
                scope: resource:read
            provider:
              spring:
                authorization-uri: http://auth-server:9000/oauth/authorize
                token-uri: http://auth-server:9000/oauth/token
    

    在来自 OP 的示例中,OAuth2AuthorizedClientManager 支持 client_credentials 授权以发出访问令牌请求。这对前很有用。如果我们想实现以下(虚构的)端点:

    @RestController
    public class TokenController {
        @GetMapping("/token")
        public OAuth2AccessToken token(@RegisteredOAuth2AuthorizedClient("test-client") OAuth2AuthorizedClient testClient) {
            return testClient.getAccessToken();
        }
    }
    

    OAuth2AuthorizedClientManager 提供了在此示例中注入的 OAuth2AuthorizedClient。它可以配置自定义转换器,如下所示:

    注意:以下是改编自参考文档的Client Credentials section 的扩展示例。

        @Bean
        public OAuth2AuthorizedClientManager authorizedClientManager(
                ClientRegistrationRepository clientRegistrationRepository,
                OAuth2AuthorizedClientRepository authorizedClientRepository) {
            // @formatter:off
            OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                    .clientCredentials((builder) ->
                        builder.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient())
                            .build())
                    .build();
    
            DefaultOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultOAuth2AuthorizedClientManager(
                    clientRegistrationRepository, authorizedClientRepository);
            authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
            // @formatter:on
    
            return authorizedClientManager;
        }
    
        @Bean
        public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
            // @formatter:off
            OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter =
                new OAuth2ClientCredentialsGrantRequestEntityConverter();
            requestEntityConverter.setHeadersConverter(headersConverter());
    
            DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
                new DefaultClientCredentialsTokenResponseClient();
            accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
            // @formatter:on
    
            return accessTokenResponseClient;
        }
    
        private static <T extends AbstractOAuth2AuthorizationGrantRequest> Converter<T, HttpHeaders> headersConverter() {
            // @formatter:off
            Converter<T, ClientRegistration> clientRegistrationConverter =
                AbstractOAuth2AuthorizationGrantRequest::getClientRegistration;
            return clientRegistrationConverter
                .andThen((clientRegistration) -> {
                    HttpHeaders headers = new HttpHeaders();
                    headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));
                    headers.setContentType(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"));
                    headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
                    return headers;
                });
            // @formatter:on
        }
    

    如果我们想支持authorization_code 授权登录应用程序,我们可以使用以下配置(包含上述方法和@Bean 定义):

    @EnableWebSecurity
    public class SecurityConfiguration {
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                .authorizeRequests(authorizeRequests -> authorizeRequests
                    .anyRequest().authenticated())
                .oauth2Login(oauth2Login -> oauth2Login
                    .tokenEndpoint(tokenEndpoint -> tokenEndpoint
                        .accessTokenResponseClient(authorizationCodeAccessTokenResponseClient())));
            // @formatter:on
    
            return http.build();        
        }
    
        @Bean
        public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
            // @formatter:off
            OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
                new OAuth2AuthorizationCodeGrantRequestEntityConverter();
            requestEntityConverter.setHeadersConverter(headersConverter());
    
            DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
                new DefaultAuthorizationCodeTokenResponseClient();
            accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
            // @formatter:on
    
            return accessTokenResponseClient;
        }
    
        // ...
    
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-19
      • 2019-06-04
      • 1970-01-01
      • 2012-01-17
      • 2018-06-24
      • 2015-09-18
      • 1970-01-01
      • 2021-06-10
      • 2019-04-11
      相关资源
      最近更新 更多