如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源? [英] How can I use client_credentials to access another oauth2 resource from a resource server?

查看:49
本文介绍了如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 client_credentials 从反应式资源服务器访问另一个受 oauth2 保护的资源.我使用发布的令牌访问资源服务器的部分正在工作,但没有使用 webclient 调用其他资源.

I want to use client_credentials to access another oauth2-protected resource from a reactive resource-server. The part where I'm accessing the resource server using an issued token is working, but not calling the other resource using webclient.

使用 UnAuthenticatedServerOAuth2AuthorizedClientRepository 我得到 serverWebExchange must be null,使用 AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository 我得到 principalName must be null.

Using UnAuthenticatedServerOAuth2AuthorizedClientRepository I get serverWebExchange must be null, and using AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository I get principalName must be null.

使用 https://www.baeldung.com/spring-webclient-oauth2 只要我将客户端称为 CommandLineRunner 就可以工作.我在 stackoverflow 上找到的其他建议都没有奏效.

Using https://www.baeldung.com/spring-webclient-oauth2 works as long as I call the client as a CommandLineRunner. None of the other suggestions I have found here on stackoverflow has worked.

我在这里错过了什么?我使用的是 Spring Security 5.2.0 和 Spring Boot 2.2.0.

What am I missing here? I am using Spring Security 5.2.0 and Spring Boot 2.2.0.

客户端配置:

@Configuration
public class ClientSecurityConfig {

    // UnAuthenticatedServerOAuth2AuthorizedClientRepository version

    @Bean
    WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
                new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());

        return WebClient.builder()
                .filter(oauth)
                .build();
    }

    @Bean
    ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider(CustomClientConfig clientConfig) {
        return ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials(clientCredentialsGrantBuilder ->
                                clientCredentialsGrantBuilder.accessTokenResponseClient(new CustomClient(clientConfig))) // Used to send extra parameters to adfs server
                        .build();
    }


    // AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository version

    @Bean
    WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
                new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        return WebClient.builder()
                .filter(oauth)
                .build();
    }
}

    @Bean
    ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ServerOAuth2AuthorizedClientRepository authorizedClientRepository, CustomClientConfig clientConfig) {

        ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
                ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials(clientCredentialsGrantBuilder ->
                                clientCredentialsGrantBuilder.accessTokenResponseClient(new CustomClient(clientConfig))) // Used to send extra parameters to adfs server
                        .build();
        DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }
}

资源服务器配置:

@EnableWebFluxSecurity
class ResourceServerConfig {
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                .authorizeExchange(exchanges ->
                        exchanges
                                .pathMatchers("/actuators/**", "/api/v1").permitAll()
                                .pathMatchers("/api/v1/**").hasAuthority("SCOPE_read")
                                .anyExchange().authenticated()
                )
                .formLogin().disable()
                .httpBasic().disable()
                .oauth2Client(withDefaults())
                .oauth2ResourceServer().jwt();
        return http.build();
    }
    @RestController()
    @RequestMapping("/api/v1")
    static class Ctrl {
        final static Logger logger = LoggerFactory.getLogger(Ctrl.class);
        final WebClient webClient;

        public Ctrl(WebClient webClient) {
            this.webClient = webClient;
        }

        @RequestMapping("protected")
        Mono<JsonNode> protected(@RequestParam String data) {
            return webClient.post()
                    .uri("https://other-oauth2-protected-resource")
                    .attributes(clientRegistrationId("myclient"))
                    .bodyValue("{\"data\": \"" + data + "\"}")
                    .retrieve()
                    .bodyToMono(JsonNode.class);
        }
    }
}

application.yml:

application.yml:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://adfsserver.com/adfs/services/trust
          jwk-set-uri: https://adfsserver.com/adfs/discovery/keys
      client:
        registration:
          myclient:
            provider: adfs
            client-id: <client-id>
            client-secret: <client-secret>
            authorization-grant-type: client_credentials
            scope: read
        provider:
          adfs:
            token-uri: https://adfsserver.com/adfs/oauth2/token
            jwk-set-uri: https://adfsserver.com/adfs/discovery/keys

推荐答案

最近已由 Spring 项目贡献者修复,作为此PR 但不幸的是官方 Spring 文档尚未更新.

This has recently been fixed by the Spring Project Contributors as part of this PR but unfortunately the official Spring doc is not yet updated.

正常的 servlet 方法文档是 这里如果您更喜欢选择reactive"方法,那么配置一个 webclient 只需要两个 bean:

The normal servlet approach doc is here If you prefer to choose the "reactive" approach, then configuring a webclient requires only two beans:

  1. AuthorizedClientManager Bean,以及
  2. webClient Bean

  @Bean
  public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
      ReactiveClientRegistrationRepository clientRegistrationRepository,
      ReactiveOAuth2AuthorizedClientService authorizedClientService) {

    ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
        ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
            .clientCredentials()
            .build();

    AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
        new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
            clientRegistrationRepository, authorizedClientService);
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    return authorizedClientManager;
  }


  @Bean
  public WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
    return WebClient.builder().filter(oauth).build();
  }

您可以参考我的 Github Gist,其中包含所有必需的配置.

You can refer to my Github Gist which has all the required configuration.

这篇关于如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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