GraphQL 권한 부여
권한은 다음 위치에 적용될 수 있습니다.
- 유형:
- 객체 (모두
::Types::BaseObject
에서 하향되는 모든 클래스) - Enum (모두
::Types::BaseEnum
에서 하향되는 모든 클래스)
- 객체 (모두
- 리졸버:
- 필드 리졸버 (모두
::Types::BaseResolver
에서 하향되는 모든 클래스) - 뮤테이션 (모두
::Types::BaseMutation
에서 하향되는 모든 클래스)
- 필드 리졸버 (모두
- 필드 (
field
DSL 메서드를 사용하여 선언된 모든 필드)
추상 유형(인터페이스 및 연합)에 대해 권한을 지정할 수 없습니다. 추상 유형은 멤버 유형으로 위임합니다. 기본 내장 스칼라(예: 정수)에는 권한이 없습니다.
우리의 권한 부여 시스템은 애플리케이션의 나머지 부분과 동일한 DeclarativePolicy
시스템을 사용합니다.
- 단일 값(예:
Query.project
)의 경우 현재 인증 된 사용자가 권한을 충족하지 못하면 필드는null
로 해결됩니다. - 컬렉션(예:
Project.issues
)의 경우 사용자의 권한 부여 확인에 실패한 객체가 제외된 컬렉션으로 필터링됩니다. 이 필터링 프로세스(또한 _redaction_으로 알려짐)는 페이지네이션 이후에 발생하므로 알고리즘에 의해 제거된 객체로 인해 요청된 페이지 크기보다 작을 수 있습니다.
또한 뮤테이션에서 리소스 권한 부여를 참조하십시오.
여기에서 검토 된 모든 권한 체계의 예제를 보려면 authorization_spec.rb
를 참조하십시오.
유형 권한 부여
authorize
메서드에 능력을 전달하여 유형에 권한을 부여할 수 있습니다. 동일한 유형의 모든 필드는 현재 인증 된 사용자가 필요한 능력을 가지고 있는지 확인하여 권한이 주어집니다.
예를 들어, 다음 권한 부여는 현재 인증 된 사용자가 read_project
능력을 가진 프로젝트 만 볼 수 있도록합니다 (프로젝트가 Types::ProjectType
을 사용하는 필드에서 반환되는 한):
module Types
class ProjectType < BaseObject
authorize :read_project
end
end
여러 능력에 대해 권한을 부여할 수도 있으며, 이 경우 모든 능력 확인이 통과되어야합니다.
예를 들어, 다음 권한 부여는 현재 인증 된 사용자가 프로젝트를 볼수있는 권한을 가지고 있어야합니다 read_project
및 another_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_permission
과 IssueType.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)