【问题标题】:How do I verify pacts against an API that requires an auth token?如何针对需要身份验证令牌的 API 验证协议?
【发布时间】:2016-11-24 03:13:15
【问题描述】:

我正在为我的合同测试套件使用Pact gem(并且喜欢它!)。我正在测试的 API 服务需要所有请求的授权令牌。

我知道如何为我的用户生成 API 令牌,但我不知道在 Pact 工作流程中放置令牌的位置。我在 Pact 文档和 repo 中搜索了示例,但没有任何运气。

我尝试在消费者规范中发送 POST 以生成令牌,但 Pact 模拟服务器不知道如何处理请求并输出错误(如我所料)。

我找到了this example,它看起来很有希望,特别是能够使用requestFilteraddHeader 方法为所有请求分配预定义的标头。

如何在 Pact gem 中使用这样的请求过滤器?

如果这不是当前的功能,我有什么替代方案?

更新:

J_A_X's answer 非常适合使用模拟服务器创建协议,但它不能满足 API 服务提供商对有效身份验证令牌的期望。更具体地说,我需要在运行 pact:verify 时将有效的身份验证令牌动态插入到协议中。所以,更近一步,但仍需要弄清楚后半部分。

Matthew's answer 包含关于后半部分(pact:verify)的两种可能解决方案的提示。我犹豫是否要引入另一个依赖项,所以我很想让 ProxyApp 类示例正常工作。我不明白我到底会传递给 ProxyApp.new() 什么。有什么建议吗?

【问题讨论】:

    标签: ruby pact pact-ruby


    【解决方案1】:

    实际上,除非您真的想要/需要,否则您实际上不必为每个协定交互使用真正的令牌。

    通常,对于这类东西,我只是创建一个正则表达式,用于在标题上验证某些规则,同时保持它“开放”。在我的节点项目(它在后面使用 Ruby 二进制文件)中,我创建了这 2 个实用程序函数来创建具有模式的对象和另一个用于对象最小相等的对象:

    function term(matcher, generate) {
        if ((typeof matcher === 'undefined') || (typeof generate === 'undefined')) {
          throw 'Matcher and Generate arguments must be specified to use Term';
        }
        return {
          "json_class": "Pact::Term",
          "data": {
            "generate": generate,
            "matcher": {
              "json_class": "Regexp",
              "o": 0,
              "s": matcher
            }
          }
        };
      }
    
      function somethingLike(value) {
        return {
          "json_class": "Pact::SomethingLike",
          "contents": value
        };
      }
    

    然后你可以像这样在你的 DSL 定义中使用它:

    mockService
          .given('a form')
          .uponReceiving('a GET request with a valid auth')
          .withRequest('get', '/', term('^Bearer (?!null$).+$', 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ'))
          .willRespondWith({
            status: 200,
            headers: {'Content-Type': 'application/json;charset=utf-8'},
            body: {worked:true}
          });
    

    “term”实用程序有一个正则表达式作为第一个参数,然后是一个示例(应该与第一个参数匹配)在测试期间使用什么。

    我知道这需要在 Pact 内部进行更好的扩展,以使其更易于使用。我希望这会有所帮助。

    【讨论】:

    • 感谢您的详尽回答!您的示例确实有效,尽管它对我来说更像是一种解决方法。我希望有一种内置方法可以让我使用真正的身份验证令牌验证协议。
    • 好吧,您可以使用它们,但这里的问题是您现在必须在创建交互之前知道该令牌将是什么,然后对其进行测试。我不知道如何在不以某种方式作弊的情况下轻松创建该流程,这与这样做基本相同。最后,问问自己这个特定的交互检查在你的提供者的整体测试中是否真的那么重要。在我看来,它不是,因此是我的正则表达式;对我来说重要的是能够以正确格式/类型返回数据的业务 API。
    • 您的方法非常适合使用模拟服务器创建协议,但它不能满足 API 服务提供商对有效身份验证令牌的期望。更具体地说,我需要在运行 pact:verify 时将有效的身份验证令牌动态插入到协议中。这有意义吗?
    • @mycargus 如果您使用术语匹配器,您可以添加一个有效的令牌作为“生成器”,它应该在您的合同中对其进行验证,但是具有“有效”身份验证的问题令牌通常会过期,因此使用令牌通常会在过期后使真实代码失败,除非您想在代码中继续更新该令牌。我相信这是使用 Pact 的一个边缘案例,令牌验证是用于单元测试的,而合约仍然可以验证所需的标头和格式,如“授权:承载。*”
    • 也许我误解了 Pact 在 pact:verify 上的作用。它不会重播 Pact 文件中定义的请求吗?如果是这样,它将使用其中定义的相同身份验证令牌......如果这些令牌无效,那么 API 服务将响应 401。这就是我目前面临的问题。使用您的解决方案,我可以生成 Pact 文件,并且可以断言实际请求具有适合提供的正则表达式的标头...但是如何将有效的身份验证令牌插入到请求中?那是我的问题。在生成协议文件时,我不能依赖生成有效的令牌,因为它可能会过期。
    【解决方案2】:

    Pact 的 Ruby 实现并不像 JVM 实现那样直接支持这一点。

    如果您使用的是 Pact Provider Proxy gem,您可以查看https://github.com/realestate-com-au/pact/issues/49#issuecomment-65346357https://groups.google.com/forum/#!topic/pact-support/tSyKZMxsECk 中讨论的一些选项。

    一个例子可能类似于:

    class ProxyApp
    
      def initialize real_app
        @real_app = real_app
      end
    
      def call env
        @real_app.call(env.merge('HTTP_AUTHORIZATION' => '12345'))
      end
    end
    
    Pact.service_provider "Some Provider" do
      app do
        ProxyApp.new(RealApp)
      end
    
      honours_pact_with "Some Consumer" do
        #...
      end
    end
    

    【讨论】:

    • 我会考虑使用提供者代理。谢谢!
    • 我现在看到您推荐了两种不同的可能解决方案:(1) 使用 Pact Provider 代理来验证针对单独运行的提供程序的协定,或者 (2) 在提供程序的 pact_helper 中使用一个类。 rb 将动态身份验证标头合并到协议验证中。我现在正在尝试第二种方法。
    • 谢谢@mycargus,我很想听听你的情况。这可能是进入我们文档的一个很好的例子,因为它不时出现。
    • 酷,我一定会分享的。我很想让 ProxyApp 类示例工作。我不明白我到底会传递给 ProxyApp.new() 什么。我猜是 Rails 应用程序,但我不知道该怎么做。建议?
    • 我会问 Ruby 中的某个人,看看他们是否能提供任何启示。同时,我在docs.pact.io/faq 中添加了一个开头
    猜你喜欢
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-28
    相关资源
    最近更新 更多