수학과의 좌충우돌 프로그래밍

[Django] APIView에 permission 지정하기 본문

웹프로그래밍/DRF

[Django] APIView에 permission 지정하기

ssung.k 2020. 2. 26. 12:48

Django-Authentication-Permissions

 

[Django] Authentication 과 Permissions

DRF 에서의 접근제한을 알아보도록 하겠습니다. 우선 기본적으로 접근제한을 제외한 기본적인 코드들에 대해서는 설명을 생략하겠습니다. 앞의 포스팅들을 참고해주세요. 현재 까지의 진행 상황은 다음과 같습니다..

ssungkang.tistory.com

저번 포스팅에서 django rest framework 에서의 AuthenticationPermissions 에 대해서 알아보았습니다.

이번 포스팅에서는 APIView에서 Permissions 을 사용해보도록 하겠습니다.

 

Custom Permission

우선 사용할 두 개의 Custom Permission을 만들어보겠습니다.

여러 app의 views 에서 사용할 것이기 때문에 config에 permissions을 만들고 그 안에 정의해주었습니다.

기본적으로 Custom Permission 들은 BasePermission 을 상속받아 작성하게 됩니다.

# config/permissions.py

from django.contrib.auth import get_user_model
from rest_framework.permissions import BasePermission, SAFE_METHODS

class IsOwnerOnly(BasePermission):
    # 작성자만 접근
    def has_object_permission(self, request, view, obj):
        if request.user.is_authenticated:
            # 관리자
            if request.user.role == '10':
                return True
            elif hasattr(obj, 'profile'):
                return obj.profile.id == request.user.id
            elif obj.__class__ == get_user_model():
                return obj.id == request.user.id
            return False
        else:
            return False

먼저 살펴본 permissions 은 IsOwnerOnly 입니다.

has_object_permission 은 특정 object에 접근하는 순간 권한을 확인해줍니다.

  • 9번째 줄에서 유저가 로그인되었는지 확인합니다.

  • 11번째 줄에서 유저의 role이 10일 경우, 관리자이므로 모든 권한을 허락합니다.

  • 13번째 줄에서 해당 obj가 profile 이라는 필드를 가지고 있는 경우 해당 필드의 id 와 접근하는 유저의 id를 비교하여 권한을 허락합니다.

    이에 대해 예시를 통해 좀 더 설명하자면 Review 라는 모델에 대해서 권한을 부여할 때는 Reivew 모델이 아닌 Review 모델의 작성자를 확인해줘야합니다.

    class Review(models.Model):
        profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
        ...
    

    Review 모델은 다음과 같이 profile 필드가 있기 때문에 이를 통해 권한을 확인하게 됩니다.

  • 15번째 줄에서는 obj의 클래스가 유저일 경우 직접 id 비교를 통해 권한을 부여하게 됩니다.

 

class IsOwnerOrReadOnly(BasePermission):
    # 작성자만 접근, 작성자가 아니면 Read만 가능
    def has_object_permission(self, request, view, obj):
        if request.user.is_authenticated:
            if request.user.role == '10':
                return True
            # 값을 바꾸지 않는 안전한 method
            elif request.method in SAFE_METHODS:
                return True
            elif hasattr(obj, 'profile'):
                return obj.profile.id == request.user.id
            elif obj.__class__ == get_user_model():
                return obj.id == request.user.id
            return False
        else:
            return False

두 번째로는 IsOwnerOrReadOnly 입니다.

위와 다른 점은 8번째 줄에 새로운 구문이 추가되어 있습니다.

SAFE_METHODS 는 db 를 수정하지 않는 GET, HEAD, OPTIONS 등이 있습니다.

해당 요청의 경우에는 작성자가 아니더라도 요청을 허락해주는 permission 입니다.

 

APIView에 사용

permission에 has_object_permission 이 아닌 has_permission 은 해당 요청이 들어올 때 항상 실행이 됩니다.

has_object_permission 이 들어오기 전에도 has_permission 을 우선 거친 후 실행이 되고 APIView에서 역시 자동으로 실행이 됩니다.

하지만 has_object_permission 의 경우 별도의 호출 과정이 필요합니다.

class ReviewDetailView(APIView):
    permission_classes = [IsOwnerOrReadOnly]

    def get_object(self, review_id):
        try:
            review = Review.objects.get(id=review_id)
            self.check_object_permissions(self.request, review)
            return review
        except ObjectDoesNotExist:
            return None

    def get(self, request, id, review_id):

다음과 같이 get_object 함수 내에서 check_object_permissions 을 통해 has_object_permission 을 호출할 수 있습니다.

첫번째 인자로는 request가 두번째 인자로는 obj가 들어가게 됩니다.

Comments