在测试中替换 OAuth2 WebClient

2024-05-30

我有一个小型 Spring Boot 2.2 批次,用于写入 OAuth2 REST API。

我已经能够配置WebClient下列的https://medium.com/@asce4s/oauth2-with-spring-webclient-761d16f89cdd https://medium.com/@asce4s/oauth2-with-spring-webclient-761d16f89cdd它按预期工作。

    @Configuration
    public class MyRemoteServiceClientOauth2Config {

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

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

    }

但是,现在我想为我的批次编写集成测试,并且我想避免使用“真实”授权服务器来获取令牌:如果外部服务器关闭,我不希望我的测试失败。我希望我的测试是“自主的”。

我正在调用的远程服务被替换为mockserver在我的测试期间假的。

在这种情况下,最佳做法是什么?

  • 对我有用的是仅在测试之外启用上述配置@Profile("!test")并运行我的测试@ActiveProfiles("test")。我还在测试中导入了测试特定配置:
    @Configuration
    @Profile("test")
    public class BatchTestConfiguration {

        @Bean("myRemoteService")
        public WebClient webClientForTest() {

            return WebClient.create();
        }

    }

但我觉得必须补充一下@Profile("!test")在我的生产配置上不是很好..

  • 有没有一种“更干净”的方法来替换我正在使用的 WebClient bean,通过调用我的假远程服务而无需先尝试获取令牌的方法?我试着放一个@Primary在我的 webClientForTest bean 上,但它不起作用:生产 bean 仍然启用,并且出现异常:

没有类型为“org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository”的合格 bean

这是生产bean需要的参数类型

  • 作为测试的一部分,我是否需要启动一个假授权服务器并配置 WebClient 以从中获取虚拟令牌?是否有一个库可以尽可能开箱即用地提供此功能?

我和你的情况一样,找到了解决办法。首先,为了看到它的实际效果,我创建了一个具有展示实施的存储库 https://github.com/clocken/spring-webclient-oauth2-login-mock下面解释的所有内容。

有没有一种“更干净”的方法来替换我正在使用的 WebClient bean,通过调用我的假远程服务而无需先尝试获取令牌的方法?

我不会更换WebClientbean 在你的测试中,而是替换ReactiveOAuth2AuthorizedClientManager https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientManager.html豆与模拟。 为此,您必须稍微修改您的MyRemoteServiceClientOauth2Config。而不是使用现在已弃用的方法UnAuthenticatedServerOAuth2AuthorizedClientRepository https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/web/server/UnAuthenticatedServerOAuth2AuthorizedClientRepository.html你这样配置(这样也比较符合Servlet-Stack 上的记录配置 https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2Client-webclient-servlet):

@Configuration
public class MyRemoteServiceClientOauth2Config {

    @Bean
    public WebClient webClient(ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2ClientCredentialsFilter =
                new ServerOAuth2AuthorizedClientExchangeFilterFunction(reactiveOAuth2AuthorizedClientManager);
        oauth2ClientCredentialsFilter.setDefaultClientRegistrationId("myRemoteService");

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

    @Bean
    public ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager(ReactiveClientRegistrationRepository clientRegistrations,
                                                                                       ReactiveOAuth2AuthorizedClientService authorizedClients) {
        AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
                new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, authorizedClients);

        authorizedClientManager.setAuthorizedClientProvider(
                new ClientCredentialsReactiveOAuth2AuthorizedClientProvider());

        return authorizedClientManager;
    }
}

然后你可以创建一个模拟ReactiveOAuth2AuthorizedClientManager总是返回一个Mono https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html of an OAuth2AuthorizedClient https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.html像这样:

@TestComponent
@Primary
public class AlwaysAuthorizedOAuth2AuthorizedClientManager implements ReactiveOAuth2AuthorizedClientManager {

    @Value("${spring.security.oauth2.client.registration.myRemoteService.client-id}")
    String clientId;

    @Value("${spring.security.oauth2.client.registration.myRemoteService.client-secret}")
    String clientSecret;

    @Value("${spring.security.oauth2.client.provider.some-keycloak.token-uri}")
    String tokenUri;

    /**
     * {@inheritDoc}
     *
     * @return
     */
    @Override
    public Mono<OAuth2AuthorizedClient> authorize(final OAuth2AuthorizeRequest authorizeRequest) {
        return Mono.just(
                new OAuth2AuthorizedClient(
                        ClientRegistration
                                .withRegistrationId("myRemoteService")
                                .clientId(clientId)
                                .clientSecret(clientSecret)
                                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                                .tokenUri(tokenUri)
                                .build(),
                        "some-keycloak",
                        new OAuth2AccessToken(TokenType.BEARER,
                                "c29tZS10b2tlbg==",
                                Instant.now().minus(Duration.ofMinutes(1)),
                                Instant.now().plus(Duration.ofMinutes(4)))));
    }
}

最后@Import在你的测试中:

@SpringBootTest
@Import(AlwaysAuthorizedOAuth2AuthorizedClientManager.class)
class YourIntegrationTestClass {

  // here is your test code

}

相应的src/test/resources/application.yml看起来像这样:

spring:
  security:
    oauth2:
      client:
        registration:
          myRemoteService:
            authorization-grant-type: client_credentials
            client-id: test-client
            client-secret: 6b30087f-65e2-4d89-a69e-08cb3c9f34d2 # bogus
            provider: some-keycloak
        provider:
          some-keycloak:
            token-uri: https://some.bogus/token/uri

选择

你也可以使用相同的mockserver您已经在使用模拟您的 REST 资源、模拟授权服务器并响应令牌请求。为此,您需要配置mockserver as the token-uri in the src/test/resources/application.yml或您用来分别为测试提供属性的任何内容。


Notes

注射WebClient直接地

推荐的提供方式WebClient在你的豆子中是通过注入WebClient.Builder,得到预配置的 https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient通过Spring Boot。这也保证了,WebClient您的测试中的配置与生产中的配置完全相同。您可以声明WebClientCustomizer豆类进一步配置此构建器 https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient-customization。这就是它在上面提到的我的展示存储库中实现的方式。

Bean 覆盖/优先级@Primary on a @Bean里面一个@Configuration or @TestConfiguration

我也尝试过,发现它并不总是按照人们期望的方式工作,可能是因为 Spring 加载和实例化 bean 定义的顺序。例如,ReactiveOAuth2AuthorizedClientManager仅当以下情况时才使用模拟@TestConfiguration is a static nested测试类中的类,但如果是则不是@Import编辑。拥有static nested @TestConfiguration在接口上并用测试类实现它也不起作用。所以,为了避免这样说static nested我需要的每个集成测试的课程,我宁愿选择@TestComponent这里介绍的方法。

其他 OAuth 2.0 授权类型

我只测试了我的方法Client Credentials拨款类型,但我认为它也可以针对其他拨款类型进行调整或扩展。

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

在测试中替换 OAuth2 WebClient 的相关文章

随机推荐

  • 检测 html 选择框上的编程更改

    有没有办法让 HTML 选择元素在每次以编程方式更改其选择时调用函数 当使用 JavaScript 修改选择框中的当前选择时 IE 和 FF 都不会触发 onchange 此外 更改选择的 js 函数是框架的一部分 因此我无法更改它以在结束
  • 如何在react.js中将/n替换为换行符?

    我正在尝试更换每一个 n to a br tag in ReactJS In my note note对象有一个包含多个的字符串 n in it 示例注释 注释 test ntest ntest 我尝试过的ReactJS note note
  • C 中函数“fgets”的参数太少

    每当我编译这个错误时 我都会收到该错误 但我不知道为什么 我直接从书上抄袭这个 有人可以帮忙吗 include
  • 有角。 [HMR] 无法应用更新。需要完全重新加载

    我添加 HMR 故事配置 hmr https github com angular angular cli wiki stories configure hmr 到我的 Angular 项目 但不是热重新加载 而是完全重新加载 更新到Ang
  • 如何在 Bash 脚本中查找数字的阶乘?

    在 shell 脚本中如何查找数字的阶乘 seq s 1 500 bc
  • 使用 file_get_contents 在 php 中进行屏幕缩放

    嗨 我对屏幕抓取很陌生 我正在尝试从酒店预订网站上抓取评论以显示在我的网站上 我已经走到这一步了 但有点卡住了 有人可以帮忙吗 use 文档 http php net manual en class domdocument ph
  • 如何使用 Matplotlib 可视化标量二维数据?

    所以我有一个网格网格 矩阵 X 和 Y 以及标量数据 矩阵 Z 我需要将其可视化 最好是一些 2D 图像 在各点处带有颜色 显示 Z 值 我做了一些研究 但没有找到任何能完全满足我想要的效果的东西 pyplot imshow Z 看起来不错
  • Scala 匿名函数中的 return 语句

    为什么显式 return 语句 使用return关键字 在匿名函数中从封闭的命名函数返回 而不仅仅是从匿名函数本身返回 例如 以下程序会导致类型错误 def foo String x Integer gt return x foo 我知道建
  • 安装 gplots 时出错

    我正在 OSX v 10 9 2 上运行 R v 3 0 3 当尝试使用以下命令在 R studio 中安装 gplots 包时 出现错误 gt library gplots Error in library gplots there is
  • javascript 闭包和对象引用

    我的情况有点晦涩难懂 主要是因为我认为我已经掌握了闭包 所以基本上我想要的是将集合重置为默认值 假设我有一个集合 它具有带有对象参数数组的构造函数 var c new collection x y z 然后集合定期更新 因为我没有保留数组的
  • 未生成 appxupload 包。仅生成测试包

    我正在开发一个通用的 Windows 应用程序 当我尝试使用商店 gt 创建应用程序包创建包时 它仅创建测试包 在AppPackages目录中 我只能找到一个带有 test的文件夹 如何确保创建的 appxupload 包可以上传到 Win
  • javascript从字符串创建不区分大小写的正则表达式

    我试图通过以不区分大小写的方式将输入与正则表达式匹配来进行验证 正则表达式作为对象上的字符串从服务中下来 我可能会得到类似的东西 regex ane 我可以执行以下操作 var rx new RegExp object regex The
  • 无法使用 Alarmmanager 定期在后台进行工作

    我想按小时在后台调用一项服务 第一个问题是警报管理器工作不顺利 计时器很糟糕 有时早有时晚 第二个问题是 RemoteServiceException Context startForegroundService 然后没有调用 Servic
  • 不兼容的指针到字符转换

    我正在编写一个程序 将卡片值写入 52 个点字符的多维数组中 该程序是一个测试数组 稍后我将其作为函数写入主程序中 在程序中 我通过以下方式初始化 for 循环计数0通过51 我用一个switch语句调制13将卡牌值分配给数组点 但是 我收
  • iOS swift 应用程序启动时出现黑屏

    我有个问题 当我启动我的应用程序时 会看到黑屏几秒钟 然后出现启动屏幕 我的启动画面不是默认的 我使用了视图控制器 因为我的启动画面有一个动画 我搜索了一个解决方案 我得到了这个 在我的闪屏加载 iPhone 之前出现黑屏 https st
  • Oreo:应用程序未运行时不会触发警报

    我有相对简单的设置 应该在一天中的特定时间触发警报并向用户显示通知 这是相关代码 设置闹钟 long inTime expirationTime Calendar getInstance getTimeInMillis 10000 Inte
  • Kubernetes - 滚动更新杀死旧的 Pod,而不启动新的 Pod

    我目前正在使用 Deployments 来管理 K8S 集群中的 pod 我的一些部署需要 2 个 pod 副本 一些需要 3 个 pod 副本 还有一些只需要 1 个 pod 副本 我遇到的问题是只有一个 pod 副本 我的 YAML 文
  • R:中断 for 循环

    你能确认下一个break是否取消了内部for循环吗 for out in 1 n old id velho lt old table df id out for in in 1 n id novo lt new table df ID in
  • 您的 C++ 程序中是否仍然存在内存分配失败问题 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我正在为公司写一些指导方针 我需要回答一些棘手的问题 这一项是相当困难的 解决方案可以是 根本不跟踪 确保使用 new 分配对象 这会在分配失败
  • 在测试中替换 OAuth2 WebClient

    我有一个小型 Spring Boot 2 2 批次 用于写入 OAuth2 REST API 我已经能够配置WebClient下列的https medium com asce4s oauth2 with spring webclient 7