1

这是使用标准 graphql-ruby 设置时发生的数据泄漏的示例。

使用下面的 graphql 嵌套请求,响应返回嵌套在公司 1 下的数据,该数据属于公司 2。我希望响应仅限于属于它嵌套的公司的会计日志。

那样的话,就是在泄露信息。

问题是我们如何修补泄漏,以便响应中返回的唯一数据及其嵌套对象是属于公司的数据(根对象)。

这个查询:

query { 
  company(id: "1") {
    id
    name
    activityLog {
      id
      activityAt
      accountant {
        id
        name
      }
      companyId
    }
    accountants {
      id
      name
      activityLog {
        id
        activityAt
        companyId
      }
    }
  }
}

返回此响应:

{
  "data": {
    "company": {
      "id": "1",
      "name": "AwsomeCo",
      "activityLog": [
        {
          "id": "1",
          "activityAt": "2019-10-12 16:40:13 UTC",
          "accountant": {
            "id": "100",
            "name": "Mr Smith",
          },
          "companyId": "1"
        }
      ],
      "accountants": [
        {
          "id": "100",
          "name": "Mr Smith"
          "activityLog": [
            {
              "id": "1",
              "activityAt": "2019-10-12 16:40:13 UTC",
              "companyId": "1"
            },
            {
              "id": "2",
              "activityAt": "2019-10-11 16:40:13 UTC",
              "companyId": "2"  // OTHER COMPANY, NEED TO PRESERVE PARENT SCOPE
            },
          ],
        }
      }
    }
  }
}

在公司 1 的嵌套元素中泄露公司 2 的事务日志数据。

同样,问题是:我们如何保持范围,仅在所显示的公司的上下文中显示数据?

重现代码:

GraphQL 类型(使用 graphql-ruby gem)

#query_type.rb
module Types
  class QueryType < Types::BaseObject
    # Add root-level fields here.
    # They will be entry points for queries on your schema.
    field :company_leak, Types::ExampleLeak::CompanyType, null: false do
      argument :id, ID, required: true
    end
    field :companies_leak, [ Types::ExampleLeak::CompanyType ], null: false

    def company_leak(id: )
      Company.find(id)
    end

    def companies_leak
      Company.all
    end
  end
end

module Types
  module ExampleLeak
    class CompanyType < BaseObject
      field :id, ID, null: false
      field :name, String, null: false
      field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true
      field :accountants, [Types::ExampleLeak::AccountantType], null: true
    end
  end
end

module Types
  module ExampleLeak
    class AccountantType < BaseObject
      field :id, ID, null: false
      field :name, String, null: false
      field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true
      field :companies, [Types::ExampleLeak::CompanyType], null: true
    end
  end
end

module Types
  module ExampleLeak
    class TransactionLogType < BaseObject
      field :id, ID, null: false
      field :activity_at, String, null: false
      field :company_id, ID, null: false
      field :accountant, Types::ExampleLeak::AccountantType, null: false
    end
  end
end

楷模

class Company < ApplicationRecord
  has_and_belongs_to_many :accountants
  has_many :transaction_logs
end

class Accountant < ApplicationRecord
  has_and_belongs_to_many :companies
  has_many :transaction_logs
end

class TransactionLog < ApplicationRecord
  belongs_to :company
  belongs_to :accountant
end

种子.rb

awesomeco = Company.create!(name: 'AwesomeCo')
boringco = Company.create!(name: 'BoringCo') 
mr_smith = Accountant.create!(name: "Mr. Smith")
awesomeco.accountants << mr_smith
boringco.accountants << mr_smith
mr_smith.transaction_logs.create!(company: awesomeco, activity_at: 1.day.ago)
mr_smith.transaction_logs.create!(company: boringco, activity_at: 2.days.ago)

包含完整代码的公共回购,旨在作为教育资源:

https://github.com/rubynor/graphql-ruby-training-ground

4

2 回答 2

1

我们可以class AccountantType < BaseObject按如下方式更新字段来解析事务日志:

  field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true,
    resolve: ->(obj, args, ctx) {
      company_leak = ctx.irep_node.parent.parent.arguments[:id]
      companies_leak = ctx.parent.parent.object.object.id
      TransactionLog.where(id: company_leak.present? ? company_leak : companies_leak)
    }

如果给公司 ID 一个参数,它将根据该 ID 获取事务日志,否则相对于其父级Accountant

于 2019-10-28T08:58:22.577 回答
0

听起来像是 Pundit 和范围界定的完美用例。这样,鉴于验证了他们的查询的用户将自动确定正确的公司范围

于 2020-03-02T19:29:49.993 回答