[참고 문헌]
만약, 퍼미션을 세팅하지 않으면 누구나 애플리케이션에 접근할 수 있다. 이 디폴트 상태의 코드는 아래와 같다.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
만약 애플리케이션에 대해 단지 인증된 사용자만 접근하게 하려면, settings.py에서 아래 코드를 추가해 주면 된다.
[setting.py]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
하지만 통상 웹서비스에서는 특정 뷰 혹은 클래스에서 인증을 요함으로 좀 더 작은 단위로 쪼개서 Permission을 설정해 주어야 한다.
Object Level과 Field Level로 나눠서 퍼미션 세팅을 해 줄 수 있다.
먼저 테스트를 위해 admin 계정 하나와 유저 계정 하나를 만든다.
그리고 아래 코드를 작성해서 퍼미션를 설정해 준다.
IsAuthenticatedOrReadOnly 클래스는 누구나 다 읽을 수는 있지만, 다른 기능(생성/수정/삭제)는 인증된 사용자만 접근가능하게 하는 클래스이다. 로그인한 유저가 해당 API에 접근하면 DRF API 웹화면에서 POST가 활성화되지만, 로그인 하지 않은 유저는 비활성화된다.
[api/views.py]
from rest_framework import permissions
class EbookListCreateAPIView(generics.ListCreateAPIView):
queryset = Ebook.objects.all().order_by("id")
serializer_class = EbookSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
2-1) permissions.py 작성
[permissions.py]
from rest_framework import permissions
class IsAdminUserOrReadOnly(permissions.IsAdminUser):
def has_permission(self, request, view):
is_admin = super().has_permission(request, view)
return request.method in permissions.SAFE_METHODS or is_admin
2-2) views.py 수정
[api/views.py]
from ebooks.api.permissions import IsAdminUserOrReadOnly
class EbookListCreateAPIView(generics.ListCreateAPIView):
queryset = Ebook.objects.all().order_by("id")
serializer_class = EbookSerializer
permission_classes = [IsAdminUserOrReadOnly]
custom permissiond을 구현하려면, BasePermission을 재정의해 다음의 메소드 중 어느 한 쪽 혹은 양 쪽 모두를 구현해야 한다.
request에 액세스 권한이 부여되면 메서드는 True를 반환하고 그렇지 않으면 False를 반환해야 한다. request가 읽기 작업인지 아니면 쓰기 작업인지 테스트해야하는 경우 'GET', 'OPTIONS'및 'HEAD'가 포함된 튜플인 SAFE_METHODS 상수와 비교하여 request 메소드를 확인해야 한다.
<예>
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
Note: view-level has_permission 검사가 이미 통과된 경우에만 인스턴스 수준의 has_object_permission 메소드가 호출된다. 또한 인스턴스 수준 검사를 실행하려면 보기 코드에서 .check_object_permissions(request, obj)를 명시적으로 호출해야 한다. generic views를 사용하는 경우 default로 이 옵션이 처리된다.
회원만 리뷰 작성할 수 있도록 함.
리뷰는 1번만 작성할 수 있도록 함.
[views.py]
from rest_framework.exceptions import ValidationError
from ebooks.api.permissions import IsAdminUserOrReadOnly, IsReviewAuthorOrReadOnly
class ReviewCreateAPIView(generics.CreateAPIView):
queryset = Review.objects.all()
serializer_class = ReviewSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
ebook_pk = self.kwargs.get("ebook_pk")
ebook = get_object_or_404(Ebook, pk=ebook_pk)
review_author = self.request.user
review_queryset = Review.objects.filter(ebook=ebook, review_author=review_author)
if review_queryset.exists():
raise ValidationError("You Have Already Reviewed this Ebook!")
serializer.save(ebook=ebook, review_author=review_author)
리뷰를 작성한 사람만 리뷰를 업데이트/삭제할 수 있도록 함.
[permissions.py]
class IsReviewAuthorOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.review_author == request.user
[views.py]
class ReviewDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Review.objects.all()
serializer_class = ReviewSerializer
permission_classes = [IsReviewAuthorOrReadOnly]