SW개발/Django

[Django]Django REST Framework - Permissions

아래의 포스팅은 DRF 공식 Documentation에 존재하는 permission에 대한 내용을 번역한 글입니다. 틀린 내용이 있을 수 있으니 헷갈리는 부분은 원문을 참고하여 주시면 감사하겠습니다.

https://www.django-rest-framework.org/api-guide/permissions/#permissions

 

Permissions - Django REST framework

 

www.django-rest-framework.org

 

Permissions

인증 또는 식별만으로는 일반적으로 정보 또는 코드에 엑세스하기에 충분하지 않다. 이를 위해서 접근을 요청하는 주체에 권한이 있어야 한다.
— Apple Developer Documentation

 

인증 및 스로틀링과 함께 권한은 요청을 허용할지 또는 거부할지에 대한 여부를 결정한다.

 

권한 체크는 다른 코드가 실행되기 전에 view의 시작과 함께 실행된다. 권한 체크는 전형적으로 request.user, request.auth에 들어오는 정보를 토대로 요청을 허용해야 하는지 여부를 결정한다.

 

권한은 서로 다른 API, 서로 다른 사용자에 대해 액세스 권한을 부여하거나 거부하는데 사용된다.

 

가장 간단한 권한 스타일은 인증된 사용자에게는 액세스를 허용하고 인증되지 않은 사용자에게는 액세스를 거부하는 것이다. 이것은 REST Framework IsAuthenticated 클래스에 해당한다.

 

약간 덜 엄격한 권한 스타일은 인증된 사용자에게 전체 액세스를 허용하고, 인증되지 않은 사용자에게는 읽기 전용 액세스만 허용하는 방법이다. 이것은 REST FrameworkIsAuthenticatedOrReadOnly 클래스에 해당한다.

 

How Permissions are determined

REST Framework의 권한은 항상 권한 클래스로서 정의한다.

 

view의 코드가 실행되기 전에 항상 각 view의 권한을 체크한다. 만약 어떠한 권한 체크가 실패하면 exceptions.PermissionDenied 또는 exceptions.NotAuthenticated 예외가 발생할 것이다. 그리고 view의 코드는 실행되지 않을 것이다.

 

권한 체크가 실패하게 된다면 "403 Forbidden" 또는 "401 Unauthorized" response가 반환될 것이다. response는 아래의 규칙을 따라서 발생한다.

  • 요청이 성공적으로 인증되었지만 권한이 거부되었을 경우
    -> HTTP 403 Forbidden response 반환
  • 요청이 성공적으로 인증되지 않았으며 우선 순위가 가장 높은 인증 클래스가 WWW-Authenticate 헤더를 사용하지 않았을 경우
    -> HTTP 403 Forbidden response 반환
  • 요청이 성공적으로 인증되지 않았으며 우선 순위가 가장 높은 인증 클래스가 WWW-Authenticate 헤더를 사용할 경우
    -> HTTP 401 Unauthorized response 반환

 

Object level permissions

REST Framework의 권한은 object-level 수준의 권한도 지원한다. Object level 권한은 일반적으로 model 인스턴스인 특정한 object에 대해 사용자 작업의 허용여부를 결정하는데 사용된다.

 

Object level 권한은 .get_object()가 호출될 때 REST Framework generic view에 의해서 실행되어진다. view level의 권한과 마찬가지로 사용자가 지정된 object에 대해 작업을 수행할 수 없는 경우에 exceptions.PermissionDenied 예외가 발생하게 된다.

 

만약 너가 view를 작성 중이고 object level의 권한을 강제로 설정하려는 경우나, generic view에서 get_object 메소드를 오버라이드하는 경우라면 object 객체를 검색한 지점의 view에서 .check_object_permissions(request, obj) 메소드를 명시적으로 호출해야 한다. 

 

이렇게 하면 PermissionDenied 또는 NotAuthenticated 예외가 발생하거나 view에 적절한 권한이 있는 경우라면 간단하게 object가 return 될 것이다.

 

For example

def get_object(self):
    obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
    self.check_object_permissions(self.request, obj)
    return obj

Note : DjangoObjectPermissions를 제외하고 rest_framework.permissions에 제공된 permission 클래스는 object 권한을 확인하는데 필요한 메서드를 구현하지 않는다.

 

object 권한을 확인하기 위해 제공된 permission 클래스를 사용하려면 Custom Permission 섹션에 설명된 것처럼 하위 클래스를 만들고 has_object_permission() 메서드를 구현해야 한다. 


Limitations of object level permissions

성능상의 이유로 generic view는 object 목록을 반환할 때 queryset의 각 인스턴스에 object level permission을 자동으로 적용하지 않는다.

 

종종 object level permission을 사용할 때 queryset을 적절하게 filterling 하여 사용자가 보기가 허용된 인스턴스만 볼 수 있도록 해야 한다.

get_object() 메소드가 호출되지 않기 때문에 object 생성시 has_object_permission() 메서드의 object level permission이 적용되지 않는다. object 생성을 제한하려면 Serializer 클래스에서 permission check를 구현하거나 ViewSet 클래스의 perform_create() 메서드를 오버라이드 해야한다.

 

Setting the permission policy

기본 권한 정책은 DEFAULT_PERMISSION_CLASSES 설정을 사용하여 전역적으로 설정할 수 있다.

For example

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

지정하지 않으면 기본적으로 무제한 액세스를 허용한다.

'DEFAULT_PERMISSION_CLASSES': [
   'rest_framework.permissions.AllowAny',
]

APIView의 class-based view를 사용하여 각 view나 viewset에 대해서 인증 정책을 설정할 수도 있다.

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

또는, function-based view라면 @api_view 데코레이터를 사용할 수 있다.

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
    content = {
        'status': 'request was permitted'
    }
    return Response(content)

Note : class 속성 또는 데코레이터를 통해 새 권한 클래스를 설정하면 settings.py 파일에 설정된 기본 list set을 무시하게 된다.

 

rest_framework.permissions.BasePermissions 에서 상속하는 경우 표준 Python 비트 연산자를 사용하여 권한을 구성할 수 있다.

예를들어, IsAuthenticatedOrReadOnly는 다음과 같이 작성할 수 있다.

from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.response import Response
from rest_framework.views import APIView

class ReadOnly(BasePermission):
    def has_permission(self, request, view):
        return request.method in SAFE_METHODS

class ExampleView(APIView):
    permission_classes = [IsAuthenticated|ReadOnly]

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

Note: &, |, ~ 연산자를 지원한다

 

728x90