代码之家  ›  专栏  ›  技术社区  ›  oma

habtm中的Graphql ruby作用域,嵌套查询中的数据泄漏

  •  0
  • oma  · 技术社区  · 6 年前

    下面是一个使用标准graphql ruby设置时发生的数据泄漏的示例。

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

    就这样,它在泄露信息。

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

    此查询:

    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

    0 回复  |  直到 6 年前
        1
  •  1
  •   Ahmad Ali    6 年前

    我们可以更新字段 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

        2
  •  0
  •   Colin Goudie    6 年前

    听起来像是专家和范围界定的完美用例。这样,给定对其查询进行身份验证的用户将自动确定正确的公司范围