본문 바로가기
Python/Django

[DRF] Permissions

by 코드뭉치 2023. 6. 10.

Permissions

 

Permissions를 가져오는 법

from rest_framework.permissions import <Permission 이름>

 

 

Permissions를 통해 View에 필요한 권한을 설정할 수 있다.


REST 프레임워크에는 특정 View에 액세스할 수 있는 사용자를

제한할 수 있는 여러 Permission class가 포함되어 있다. 

DRF에서 기본적으로 제공하는 Permission들은 다음과 같다.

  • AllowAny
  • IsAuthenticated
  • IsAdminUser
  • IsAuthenticatedOrReadOnly
  • DjangoModelPermissions
  • DjangoModelPermissionsOrAnonReadOnly
  • DjangoObjectPermissions

 

사용 예시)

class MoongTangView(APIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    ...

 

 

Custom Permissions

Custom Permissions를 생성하려면, BasePermission을 상속 후

 

다음 두 가지 중 하나 이상을 오버라이딩 해야한다.

  • .has_permission(self, request, view)
  • .has_object_permission(self, request, view, obj)

각각의 메소드는 요청에 액세스 권한을 부여해야 하는 경우 True를 반환,

그렇지 않으면 False를 반환하도록 하면 된다.



request가 READ 인지 WRITE 작업인지 테스트해야 하는 경우,

request.method를 상수 SAFE_MODES에 대해 확인해야 한다.

if request.method in permissions.SAFE_METHODS:
    # read-only 요청(GET, OPTIONS, HEAD)에 대한 권한 확인 
else:
    # write 요청(POST, UPDATE, DELETE ...)에 대한 권한 확인

 

 

객체 권한을 검사하는  has_object_permission 메서드는 

view 단위의  has_permission 검사가 이미 통과된 경우에만 호출된다.

 

또한 객체에 대한 권한을 검사하려면 View에서

.check_object_permissions(request, obj)

를 명시적으로 호출해야 한다.

 

generic views를 사용하는 경우 이는 기본적으로 처리된다.

(FBV는 개체 권한을 명시적으로 확인해야 하므로 실패 시 PermissionDenied)

Custom permissions은 테스트가 실패할 경우 PermissionDenied

 

예외와 관련된 오류 메시지를 변경하려면 custom permission에서 직접 지정해주면 된다.

 

지정하지 않았다면 PermissionDenied의 default_detail 특성이 사용



커스텀 예시)

오브젝트의 Owner이거나 ReadOnly인지 확인하는 커스텀 퍼미션.

당연하게도 객체와 유저는 관계가 있어야 한다.

아래 예시에서는 객체의 owner(user를 FK로 사용)로 유저를 판별

class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.owner == request.user

 

Admin이거나 ReadOnly인지 확인하는 커스텀 퍼미션

class IsAdminUserOrReadOnly(IsAdminUser):
    def has_permission(self, request, view):
        is_admin = super().has_permission(request, view)
        return request.method in SAFE_METHODS or is_admin

 

 

Permission의 인증과 권한에 따른 HTTP Response

요청 OK, 권한 X

> HTTP 403 Forbidden 반환


요청 X, 최우선 인증 클래스에서 WWW-Authenticate 헤더를 사용 X 

> HTTP 403 Forbidden 반환


요청 X, 최우선 인증 클래스에서 WWW-Authenticate 헤더를 사용 O

> HTTP 401 Unauthorized 반환

 

 

*참고

 

PermissionDenied의 Exception의 경우

http 상태코드(status_code),

에러코드(default_code),

에러 메시지(default_detail)로 이루어져있고,

 

이 역시 오버라이딩해서 사용 가능하다.

메시지와 코드 변경 예시)

from rest_framework import permissions

class CustomerAccessPermission(permissions.BasePermission):
    message = 'Adding customers not allowed.'
    code = 'CustomException'

    def has_permission(self, request, view):
         ...

공식문서에는 예시처럼 message와 code를 통해서 작성해주는 방법이 있고,

default_code와 default_detail을 작성해줘도 된다고 적혀있다.

댓글