如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源?

2024-02-16

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

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

Using https://www.baeldung.com/spring-webclient-oauth2 https://www.baeldung.com/spring-webclient-oauth2只要我将客户称为CommandLineRunner。我在 stackoverflow 上找到的其他建议都不起作用。

我在这里缺少什么?我正在使用 Spring Security 5.2.0 和 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);
        }
    }
}

应用程序.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 https://github.com/spring-projects/spring-security/pull/7702但不幸的是官方 Spring 文档尚未更新。

正常的 servlet 方法文档是here https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2Client-authorized-manager-provider如果您更喜欢选择“反应式”方法,那么配置 Web 客户端只需要两个 bean:

  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 要点 https://gist.github.com/abhi2495/51ad47394da2effc0fb63f97b3a78e37其中具有所有必需的配置。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源? 的相关文章

随机推荐

  • 无线 iphone 应用程序分发 - itms 服务协议问题

    我已经遵循了所有的指示Apple http developer apple com library ios featuredarticles FA Wireless Enterprise App Distribution Introduct
  • pyspark sql查询:根据条件计算不同值

    我有一个数据框如下 id doctor id patient consumption type drug d1 p1 12 0 bhd d1 p2 10 0 lsd d1 p1 6 0 bhd d1 p1
  • keras.models.load_model 失败,'tags' = train

    我正在探索tensorflow 2 0的c API 问题 将模型加载到 python 中时 权重不会恢复 因此模型似乎未经训练 工作流程 我正在使用 TF 2 0 C api 来处理模型的训练 我遵循的一般设置是 1 使用 TF keras
  • Jquery Ui拖放问题

    我正在开发一个带有 jquery 的工具栏插件以及 jquery ui 的拖放功能 这个想法如下 我有一个列表 ul 和项目 li 其中每个项目代表一个工具 如文本 几何图形等 当我拖动工具然后将其放在容器上时 必须创建一个 小部件 问题是
  • 将 PNG 图像打印到 Zebra 网络打印机

    我正在尝试找到一种将图像打印到斑马的方法 但遇到了很多麻烦 根据文档 第一种编码称为 B64 使用 MIME 对数据进行编码 Base64 方案 Base64 用于对电子邮件附件进行编码 Base64 将 6 位编码为字节 比未封装的数据扩
  • 将两种不同的颜色设置为单个容器

    I am trying to achieve a custom design dynamically from my button I have designed this button from a Container with InkW
  • “硬编码”用户代理足以让程序在多台计算机上运行吗?

    我在用着idHttp登录到一些网站并下载一些文件 我想知道因为我的程序将在具有不同窗口和软件的多台计算机上运行 例如当我说 idHttp userAgent Mozilla 5 0 Windows NT 6 1 WOW64 AppleWeb
  • 使用 pandas.to_csv 时如何指定日期格式?

    默认输出格式为to csv is 12 14 2012 12 00 00 AM 我不知道如何仅输出特定格式的日期部分 20121214 或 csv 文件中两个单独列中的日期和时间 20121214 084530 该文档太简短 无法为我提供有
  • PostgreSQL 中 json 数组值的交集

    在 PostgreSQL 9 4 中 我有一个这样的表 id array json 1 type single field id 9 type range field id 2 2 type single field id 10 type
  • 如何保持数据库表中记录的顺序

    我正在创建一个数据库表 该表将存储最终将显示在网页上的菜单链接 我的问题是我想控制菜单项的顺序 我可以有一个名为 order 的字段 但每次我有一个新的菜单链接时 我都必须插入 order 并将所有具有更高 order 的记录更改为 1 例
  • 使用 Pandas 读取 csv 时如何指定时区信息

    我有一个 csv 文件 其时间戳以 CAT 中非时间 给出 当我使用以下方法将其作为 pandas 数据框读入时 df pd read csv path parse dates timestamp dayfirst True 我收到错误 C
  • Visual Studio 2010 中的 2008 年商业智能项目(SSIS 和 SSRS)

    我必须安装什么才能从 Visual Studio 2010 创建 SQL 商业智能项目 例如 Report Services 报表和集成服务包 我是否能够创建同时适用于 SQL 2005 和 SQL 2008 的解决方案 我尝试在客户端上安
  • 如何返回最早日期的记录?

    我需要返回每个不同学生 ID 的第一条记录 在我的示例代码中 我有一个记录在同一日期发生了两个事件 而另一名学生在不同日期发生了多个事件 我需要选择最早的日期 如果同一日期发生多个事件 则将最早的事件 ID 作为下一个标准 有什么好的方法可
  • Google 地图 api - 将标记捕捉到最近的道路

    我正在尝试将坐标捕捉到最近的道路 但我仍然无法以简单的方式做到这一点 这是简单的代码 如何改进它 结果将在路上标记
  • 如何仅在 Nuxt.js 中加载客户端资源

    我正在尝试在 Nuxt js 之上使用 Tone js 构建一个应用程序 Tone js 需要浏览器的 Web Audio API 并且当 Nuxt 在服务器端渲染内容时 我的构建不断失败 Nuxt 在中解决了这个问题插件文档 https
  • 消除 Maven POM 冗余

    我有一个具有以下配置的父 POM
  • 蓝牙 LE (4.0) 有多少个中央设备可以连接到外围设备?

    我想知道一个外围设备可以同时连接多少个中心 我的问题是针对 iOS 的 但我希望得到大家的答复 有几件事 我知道中央设备 而不是外围设备 旨在处理多个连接 然而 出于各种原因 我想尝试相反的设置 来自蓝牙核心规范 V4 外围角色针对支持单一
  • django-导入-导出外部管理

    我正在尝试使用 django import export 实现简单的 xls 文件导入并保存到模型 不幸的是 这些文档仅涵盖管理集成 我被困在我的示例代码中 class UploadFileForm forms Form file form
  • 如何从 Core Data 的持久存储中删除所有对象?

    我的应用程序中有核心数据 因此 我获取一个 XML 文件 将数据解析为模型对象并将它们插入到核心数据中 它们保存在持久存储中 当我重新启动应用程序时可以访问它们 但是 我希望能够随意刷新持久存储中的数据 因此我需要首先从存储中删除现有对象
  • 如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源?

    我想使用 client credentials 从反应性资源服务器访问另一个受 oauth2 保护的资源 我使用颁发的令牌访问资源服务器的部分正在工作 但没有使用 webclient 调用其他资源 使用 UnAuthenticatedSer