GraphQL 권한 부여

권한은 다음 위치에 적용될 수 있습니다.

  • 유형:
    • 객체 (모두 ::Types::BaseObject에서 하향되는 모든 클래스)
    • Enum (모두 ::Types::BaseEnum에서 하향되는 모든 클래스)
  • 리졸버:
    • 필드 리졸버 (모두 ::Types::BaseResolver에서 하향되는 모든 클래스)
    • 뮤테이션 (모두 ::Types::BaseMutation에서 하향되는 모든 클래스)
  • 필드 (field DSL 메서드를 사용하여 선언된 모든 필드)

추상 유형(인터페이스 및 연합)에 대해 권한을 지정할 수 없습니다. 추상 유형은 멤버 유형으로 위임합니다. 기본 내장 스칼라(예: 정수)에는 권한이 없습니다.

우리의 권한 부여 시스템은 애플리케이션의 나머지 부분과 동일한 DeclarativePolicy 시스템을 사용합니다.

  • 단일 값(예: Query.project)의 경우 현재 인증 된 사용자가 권한을 충족하지 못하면 필드는 null로 해결됩니다.
  • 컬렉션(예: Project.issues)의 경우 사용자의 권한 부여 확인에 실패한 객체가 제외된 컬렉션으로 필터링됩니다. 이 필터링 프로세스(또한 _redaction_으로 알려짐)는 페이지네이션 이후에 발생하므로 알고리즘에 의해 제거된 객체로 인해 요청된 페이지 크기보다 작을 수 있습니다.

또한 뮤테이션에서 리소스 권한 부여를 참조하십시오.

note
현재 인증 된 사용자가 볼 수있는 것만로드하는 것이 최선의 방법입니다. 이는 권한 부여에 의존하지 않고 기존 찾기로드를 최소화하여 데이터베이스 쿼리 및 불필요한 권한 부여 확인을 피합니다. 또한 비밀 정보가 노출 될 수있는 단축 페이지와 같은 상황도 피할 수 있습니다.

여기에서 검토 된 모든 권한 체계의 예제를 보려면 authorization_spec.rb를 참조하십시오.

유형 권한 부여

authorize 메서드에 능력을 전달하여 유형에 권한을 부여할 수 있습니다. 동일한 유형의 모든 필드는 현재 인증 된 사용자가 필요한 능력을 가지고 있는지 확인하여 권한이 주어집니다.

예를 들어, 다음 권한 부여는 현재 인증 된 사용자가 read_project 능력을 가진 프로젝트 만 볼 수 있도록합니다 (프로젝트가 Types::ProjectType을 사용하는 필드에서 반환되는 한):

module Types
  class ProjectType < BaseObject
    authorize :read_project
  end
end

여러 능력에 대해 권한을 부여할 수도 있으며, 이 경우 모든 능력 확인이 통과되어야합니다.

예를 들어, 다음 권한 부여는 현재 인증 된 사용자가 프로젝트를 볼수있는 권한을 가지고 있어야합니다 read_projectanother_ability 능력이 필요한:

module Types
  class ProjectType < BaseObject
    authorize [:read_project, :another_ability]
  end
end

리졹버 권한 부여

리졸버에는 고유한 권한 부여가 있을 수 있으며, 이는 부모 개체에 적용되거나 해결된 값에 적용될 수 있습니다.

부모에 대해 권한이 있는 리졸버의 예는 부모가 실행되기 전에 :read_list를 충족해야하는 Resolvers::BoardListsResolver입니다.

해결된 리소스에 대한 권한을 부여하는 예는 해결된 값이 :read_pipeline를 충족해야하는 Resolvers::Ci::ConfigResolver입니다.

부모에 대한 권한 부여를 위해서는 리졸버가 authorizes_object!로 선언해야합니다 (처음에 이것이 기본 값이 아니었기 때문에 _opt in_해야합니다):

module Resolvers
  class MyResolver < BaseResolver
    authorizes_object!
    
    authorize :some_permission
  end
end

해결된 값에 대해 권한 부여하려면 리졸버는 일반적으로 #authorized_find!(**args)를 사용하여 시간을 적용해야합니다:

module Resolvers
  class MyResolver < BaseResolver
    authorize :some_permission
    
    def resolve(**args)
      authorized_find!(**args) # find_object를 호출합니다
    end
    
    def find_object(id:)
      MyThing.find(id)
    end
  end
end

이 두 가지 접근 방식 중에서 객체에 권한을 부여하는 것이 더 효율적입니다. 왜냐하면 불필요한 쿼리를 피할 수 있기 때문입니다.

필드 권한 부여

필드는 authorize 옵션을 사용하여 권한을 부여할 수 있습니다.

필드 권한 부여는 현재 개체에 대한 권한을 확인하고 해결 전에 권한이 부여되기때문에 필드가 해결된 리소스에 액세스 할 수 없을 때 권한 부여가 발생합니다. 필드에 권한 확인을 적용해야하는 경우 일반적으로 리졸버 또는 이상적으로 유형에 권한을 추가하려고합니다.

예를 들어, 다음 권한 부여는 프로젝트에 대해 관리자 수준의 액세스 권한이 있는 사용자만 secretName 필드를 볼 수 있도록합니다:

module Types
  class ProjectType < BaseObject
    field :secret_name, ::GraphQL::Types::String, null: true, authorize: :owner_access
  end
end

이 예에서 우리는 보다 비용이 많이 드는 쿼리를 피하기 위해 필드 권한 부여 (Ability.allowed?(current_user, :read_transactions, bank_account))를 사용합니다:

module Types
  class BankAccountType < BaseObject
    field :transactions, ::Types::TransactionType.connection_type, null: true,
      authorize: :read_transactions
  end
end

필드 권한 부여는 다음과 같은 경우에 권장됩니다:

  • 스칼라 필드(문자열, 부울, 또는 숫자)는 다른 필드와 다른 수준의 액세스 제어를해야합니다.
  • 부모에 대한 액세스 확인을 적용하여 필드 해결을 저장하거나 해결된 개체별로 개별 정책 확인을 피해야하는 개체 및 컬렉션 필드.

필드 권한 부여는 객체 수준의 확인을 대체하지 않으며, 부모 프로젝트의 액세스 수준과 정확히 일치하는 경우를 제외하고 필드 권한 부여를 사용해서는 안됩니다. 예를 들어 이슈는 부모의 액세스 수준과는 관계없이 비밀스러울 수 있습니다. 따라서 Project.issue에 대해 필드 권한 부여를 사용해서는 안됩니다.

또한 여러 능력에 대해 필드를 권한 부여할 수 있습니다. 단일 값으로 전달 대신 배열로 능력을 전달합니다:

module Types
  class MyType < BaseObject
    field :hidden_field, ::GraphQL::Types::Int,
      null: true,
      authorize: [:owner_access, :another_ability]
  end
end

MyType.hiddenField의 필드 권한 부여는 다음 테스트를 함축합니다:

Ability.allowed?(current_user, :owner_access, object_of_my_type) &&
    Ability.allowed?(current_user, :another_ability, object_of_my_type)

유형 및 필드 권한 부여 함께 사용

권한 부여는 누적됩니다. 즉, 현재 인증 된 사용자는 필드 및 필드 유형의 권한 요구 사항을 둘 다 통과해야 합니다.

다음 예제에서는 현재 인증 된 사용자가 이슈의 작성자를 볼 수있으려면 UserType에서 first_permissionIssueType.author에서 second_permission을 모두 가져야합니다.

class UserType
  authorize :first_permission
end
class IssueType
  field :author, UserType, authorize: :second_permission
end

UserType의 개체 권한과 IssueType.author의 필드 권한의 조합은 다음과 같은 테스트를 함축합니다:

Ability.allowed?(current_user, :second_permission, issue) &&
  Ability.allowed?(current_user, :first_permission, issue.author)