DRF - Permissions

Dongwoo Kim·2022년 9월 22일
0

DRF

목록 보기
6/9

1. Permissions

인증 과는 별개로 인가(코드에 접근을 요청하는 주체에 대한 권한)를 설정할 수 있다.

  • 인증 : 로그인과 같이 요청하는 주체가 누구인지 확인
  • 인가 : 요청하는 주체에 따라 사용가능한지 아닌지 권한 설정
  • ex)
    • 일반 사용자가 로그인 -> 인증
    • 일반 사용자는 관리자 페이지 접속 불가 -> 인가

2. Permissions 적용시키기

1) 전역 설정

1-1) 기본 권한 설정


DEFAULT_PERMISSION_CLASSES를 통해 기본 권한을 전역적으로 설정 가능하다.

# settings.py

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

1-2) Default


따로 설정하지 않으면 기본적으로 모든 접근을 허용한다.

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

2) View 설정

  • APIView 클래스를 상속받은 View 클래스에는 permission_classes 통해 권한 설정 가능
  • settings.py에 설정된 기본 설정은 무시된다.
# example_app/views.py

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)

3. Permissions 기본종류

rest_framework.permissions에서 제공하는 기본 권한 종류

1) AllowAny


요청이 인증되었는지 여부에 관계없이 무제한 액세스를 허용

2) IsAuthenticated


인증된 사용자에 대해서만 권한 허용

3) IsAdminUser


user.is_staff 설정이 True인 사용자에 대해서만 권한 서용

4) IsAuthenticatedOrReadOnly


  • 인증된 사용자는 모든 권한 허용
  • 인증되지 않은 사용자는 읽기 (GET, HEAD, OPTIONS) method 에서만 허용

5) 그밖의 Permissions


  • DjangoModelPermissions
  • DjangoModelPermissionsOrAnonReadOnly
  • DjangoObjectPermissions

4. Permissions 커스텀하기

기본 종류 외에도 BasePermission을 상속받아 권한 설정을 커스텀할 수 있다.

  • requeset.method에 대한 권한 설정 가능하다.
  • view.kwargs.get()을 통해 view의 request parameter에 접근할 수 있다.
  • 비트연산자를 통해 여러 Permissions을 구성할 수 있다.

1) 예시 - 1

  • user.type"manager"이면 모든 권한 허용
  • 아닐 경우 order_id라는 주문 식별값을 request parameter로 받아서 작성자인지 확인 후 모든 권한 허용
  • 작성자가 아닐 경우 GET, POST 메소드만 허용
# order/permissions.py

from rest_framework.permissions import BasePermission
from rest_framework.exceptions import APIException
from rest_framework import status

from order.models import Order as OrderModel

class GenericAPIException(APIException):
    def __init__(self, status_code, detail=None, code=None):
        self.status_code=status_code
        super().__init__(detail=detail, code=code)

class IsManagerOrIsAuthorOrIsAuthenticatedReadOnly(BasePermission):
    """
    관리자는 모두 가능, 작성자는 본인의 주문에 대해서만 모두 가능, 로그인 사용자는 조회, 생성만 가능
    """
    SAFE_METHODS = ('GET', 'POST')
    message = '접근 권한이 없습니다.'

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

        if not user.is_authenticated:
            response ={
                    "detail": "서비스를 이용하기 위해 로그인 해주세요.",
                }
            raise GenericAPIException(status_code=status.HTTP_401_UNAUTHORIZED, detail=response)

        if user.is_authenticated and user.type == "manager":
            return True

        order_id = view.kwargs.get('id', None)

        if order_id:
            try:
                order_author = OrderModel.objects.get(id=order_id).user
            
            except OrderModel.DoesNotExist:
                response ={
                        "detail": "주문을 찾을 수 없습니다.",
                    }
                raise GenericAPIException(status_code=status.HTTP_404_NOT_FOUND, detail=response)
        else:
            order_author = user

        if user.is_authenticated and order_author == user:
            return True

        if user.is_authenticated and request.method in self.SAFE_METHODS:
            return True
        
        return False


# order/views.py

from order.permissions import IsManagerOrIsAuthorOrIsAuthenticatedReadOnly

# 주문 CRUD View
class OrderView(APIView):
    permission_classes = [IsManagerOrIsAuthorOrIsAuthenticatedReadOnly]

    # 주문 조회
    def get(self, request, id):
        ...
        

2) 예시 - 2

비트 연산자를 통해 IsAuthenticatedOrReadOnly 작성

# example_app/views.py

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)



참고

profile
kimphysicsman

0개의 댓글