권한 부여

어디서 권한을 확인해야 하나요?

권한을 확인할 위치를 결정할 때에는 다양한 레이어에서 여러 번의 확인을 통해 방어의 깊이를 확보하세요. 낮은 수준의 레이어부터 시작하여 파인더(finders)와 서비스(services)와 같은 낮은 수준의 레이어부터 시작하여 GraphQL, 공개 REST API, 그리고 컨트롤러와 같은 고수준 레이어까지 다양한 확인을 실시하세요.

자세한 정보는 추상화 재사용을 위한 지침을 참조하세요.

동일한 자원을 여러 군데에서 보호하는 것은 하나의 방어 레이어가 침해당하거나 누락된 경우에도 고객 데이터가 추가적인 레이어에 의해 보호된다는 것을 의미합니다.

권한에 대한 자세한 정보는 보안 코딩 가이드라인의 권한 섹션을 참조하세요.

고려사항

서비스나 파인더는 적절한 위치입니다. 왜냐하면:

  • 여러 엔드포인트가 서비스나 파인더를 공유하므로 하위 로직이 재사용될 가능성이 더 높습니다.
  • 때로는 권한 부여 로직을 레코드를 필터링하는 DB 쿼리에 통합해야 할 수도 있습니다.
  • 디스플레이 레이어에서 권한 확인을 피해야 하며, UX를 개선하는 용도로만 사용해야 하며 보안 확인으로 사용해서는 안 됩니다. 예를 들어, 버튼과 같은 비데이터 요소를 보이거나 숨기는 경우 등.

방어의 깊이의 단점은 다음과 같습니다:

  • DeclarativePolicy 규칙은 비교적 성능이 우수하지만 조건문은 데이터베이스 호출을 수행할 수 있습니다.
  • 높은 유지보수 비용이 듭니다.

예외

개발자들은 특정 사례에 대한 위험과 단점을 고려한 후 권한을 단일 영역에서 처리하기로 선택할 수 있습니다.

예외를 만들 때에는 도메인 로직(서비스나 파인더)을 참조하여 진실의 근원으로 활용하세요.

백엔드 워커 로직과 같은 로직은 현재 사용자를 기반으로 한 권한 부여가 필요 없을 수 있습니다. 서비스나 파인더의 생성자가 current_user를 예상하지 않는 경우에는 일반적으로 권한을 확인하지 않습니다.

프론트엔드

UI 요소에서 능력(ability) 확인을 사용할 때, 백엔드 코드의 기반이 되는 능력 확인도 반드시 사용하세요. 이는 사용자가 적절한 액세스 권한이 있을 때만 해당 기능을 사용할 수 있도록 보장합니다.

UI 요소가 HAML인 경우, Ability.allowed?(user, action, subject)를 확인하기 위해 내장된 루비를 사용할 수 있습니다.

UI 요소가 JavaScript 또는 Vue인 경우, ApplicationController를 상속하는 모든 컨트롤러에서 사용할 수 있는 push_frontend_ability 메서드를 사용하세요. 예를 들어 다음과 같이 능력을 노출시키기 위해 이 메서드를 사용할 수 있습니다:

before_action do
  push_frontend_ability(ability: :read_project, resource: @project, user: current_user)
end

그런 다음 JavaScript에서 능력의 상태를 다음과 같이 확인할 수 있습니다:

if ( gon.abilities.readProject ) {
  // ...
}

JavaScript에서 능력의 이름은 항상 낙타 표기법(camelCase)이므로 gon.abilities.read_project를 확인하는 것은 작동하지 않습니다.

Vue 템플릿에서 능력을 확인하려면 Vue에서 능력에 액세스하는 방법에 대한 개발자 문서를 참조하세요.

클래스가 current_user를 수락하는 경우, 해당 클래스가 권한 부여를 담당할 수 있습니다.

예제: 새 API 엔드포인트 추가

기본적으로 우리는 엔드포인트에서 권한을 부여합니다. 기존 능력을 확인하는 것이 타당할 수 있습니다. 그렇지 않다면 새로운 능력을 추가해야 할 필요가 있을 것입니다.

추가적으로, 대부분의 엔드포인트는 일반적으로 리소스에 대한 CRUD(생성, 읽기, 업데이트, 삭제) 액션으로 깔끔하게 분류할 수 있습니다. 서비스 및 능력도 이와 유사하며, 이것이 많은 것들이 Projects::CreateService 또는 :read_project와 같이 명명된 이유입니다.

예를 들어, 우리가 전체 엔드포인트를 서비스로 추출한다고 가정해봅시다. can? 확인은 이제 서비스에 있을 것입니다. 만일 서비스가 우리의 목적에 맞게 수정되기 위해 기존 파인더를 재사용하면 파인더가 능력을 확인해야할까요?

  • 만일 파인더가 current_user를 받아들이지 않고 따라서 권한을 확인하지 않는다면 아마도 그렇지 않을 것입니다.
  • 만일 파인더가 current_user를 받아들이지만 권한을 확인하지 않는다면, 파인더의 다른 사용법을 다시 확인하고 권한 부여를 추가하는 것을 고려해볼 수 있습니다.
  • 만일 파인더가 current_user를 받아들이고 이미 권한을 확인한다면, 우리의 사례를 추가해야 하거나 기존의 확인이 적절한지를 확인해야 합니다.