인증(Authentication) 또는 식별(Identification)만으로는 정보나 코드에 대한 접근 권한을 얻기에 충분하지 않은 경우가 많습니다. 접근을 요청하는 엔티티는 승인(Authorization) 을 받아야 합니다.
— Apple 개발자 문서에서 인용
인증(Authentication)이나 트래픽 제한(Throttling)과 마찬가지로, 권한(Permissions)은 요청이 승인될지 거부될지를 결정합니다.
권한 확인은 뷰(View)의 가장 처음에 항상 실행되며, 다른 코드가 진행되기 전에 이루어집니다. 권한 확인은 일반적으로 request.user와 request.auth 속성에 있는 인증 정보를 사용하여 들어오는 요청이 허가되어야 하는지를 결정합니다.
권한은 다른 사용자 클래스가 API의 다른 부분에 대한 접근을 허용하거나 거부하는 데 사용됩니다.
가장 단순한 권한 스타일은 인증된 사용자에게 접근을 허용하고, 인증되지 않은 사용자에게 접근을 거부하는 것입니다. 이것은 IsAuthenticated 클래스에 해당합니다.
약간 덜 엄격한 권한 스타일은 인증된 사용자에게는 전체 접근을 허용하되, 인증되지 않은 사용자에게는 읽기 전용 접근만 허용하는 것입니다. 이것은 IsAuthenticatedOrReadOnly 클래스에 해당합니다.
REST 프레임워크에서 권한은 항상 권한 클래스 목록으로 정의됩니다.
뷰의 본문을 실행하기 전에 목록에 있는 각 권한이 확인됩니다. 권한 확인이 실패하면 exceptions.PermissionDenied 또는 exceptions.NotAuthenticated 예외가 발생하고, 뷰 본문은 실행되지 않습니다.
권한 확인이 실패하면, 요청에 따라 "403 Forbidden" 또는 "401 Unauthorized" 응답이 반환됩니다. 규칙은 다음과 같습니다:
WWW-Authenticate 헤더를 사용하지 않는 경우: HTTP 403 Forbidden 응답이 반환됩니다.WWW-Authenticate 헤더를 사용하는 경우: 적절한 WWW-Authenticate 헤더와 함께 HTTP 401 Unauthorized 응답이 반환됩니다.REST 프레임워크 권한은 객체 수준의 권한도 지원합니다. 객체 수준 권한은 사용자가 특정 객체(일반적으로 모델 인스턴스)에 대해 작업할 수 있는지 여부를 결정하는 데 사용됩니다.
객체 수준 권한은 .get_object()가 호출될 때 REST 프레임워크의 제네릭(Generic) 뷰에서 실행됩니다. 뷰 수준 권한과 마찬가지로, 주어진 객체에 대해 사용자가 작업할 수 없으면 exceptions.PermissionDenied 예외가 발생합니다.
사용자 정의 뷰를 작성하고 객체 수준 권한을 적용하거나, 제네릭 뷰에서 get_object 메서드를 재정의하려는 경우, 객체를 검색한 시점에 뷰에서 check_object_permissions(request, obj) 메서드를 명시적으로 호출해야 합니다.
이 메서드는 적절한 권한이 있으면 아무 작업도 하지 않고 그냥 반환하거나, PermissionDenied 또는 NotAuthenticated 예외를 발생시킵니다.
예시:
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
참고: DjangoObjectPermissions를 제외하고, rest_framework.permissions에서 제공하는 권한 클래스는 객체 권한을 확인하는 데 필요한 메서드를 기본으로 제공하지 않습니다.
제공된 권한 클래스를 사용하여 객체 권한을 확인하려면 해당 클래스를 서브클래싱하고 아래의 "Custom permissions(사용자 정의 권한)" 섹션에서 설명한 has_object_permission() 메서드를 직접 구현해야 합니다.
성능상의 이유로 제네릭 뷰는 객체 목록을 반환할 때 쿼리셋 내의 각 인스턴스에 대해 자동으로 객체 수준 권한을 적용하지 않습니다.
객체 수준 권한을 사용하는 경우, 사용자가 볼 수 있는 인스턴스만 확인할 수 있도록 쿼리셋을 적절하게 필터링하는 것이 일반적입니다.
또한, 객체 생성 시에는 get_object() 메서드가 호출되지 않으므로 has_object_permission() 메서드에서 객체 수준 권한이 적용되지 않습니다. 객체 생성을 제한하려면 권한 확인을 Serializer 클래스 내에서 수행하거나, ViewSet 클래스의 perform_create() 메서드를 재정의해야 합니다.
기본 권한 정책은 DEFAULT_PERMISSION_CLASSES 설정을 사용하여 전역적으로 설정할 수 있습니다. 예를 들면 다음과 같습니다:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
지정하지 않으면, 이 설정은 제한 없이 모든 접근을 허용하는 기본값으로 설정됩니다:
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
또한, APIView 클래스 기반 뷰를 사용하여 뷰별로 또는 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)
또는, 함수 기반 뷰에서 @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)
참고: 클래스 속성이나 데코레이터를 통해 새로운 권한 클래스를 설정할 때는 settings.py 파일에 설정된 기본 목록을 무시하게 됩니다.
권한이 rest_framework.permissions.BasePermission을 상속받으면 표준 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)
참고: &(and), |(or), ~(not) 연산자를 지원합니다.
AllowAny 권한 클래스는 요청이 인증되었는지 여부와 관계없이 제한 없는 접근을 허용합니다. 이 권한은 필수는 아니지만, 빈 리스트나 튜플을 사용하여 동일한 결과를 얻을 수 있지만, 명시적으로 이 클래스를 지정하면 의도를 분명히 할 수 있습니다.
IsAuthenticated 권한 클래스는 인증되지 않은 사용자에게 권한을 거부하고, 인증된 사용자에게만 권한을 허용합니다. 이 권한은 API가 등록된 사용자에게만 접근 가능하도록 하고 싶을 때 적합합니다.
IsAdminUser 권한 클래스는 user.is_staff가 True인 경우를 제외하고 모든 사용자에게 권한을 거부합니다. 이 권한은 API가 신뢰할 수 있는 관리자에게만 접근 가능하도록 하고 싶을 때 적합합니다.
IsAuthenticatedOrReadOnly 권한은 인증된 사용자에게는 모든 요청을 허용하고, 인증되지 않은 사용자에게는 GET, HEAD 또는 OPTIONS와 같은 "안전한(safe)" 메서드에 대한 요청만 허용합니다. 이 권한은 익명 사용자에게는 읽기 권한만 허용하고, 인증된 사용자에게만 쓰기 권한을 허용하고 싶을 때 적합합니다.
이 권한 클래스는 Django의 표준 django.contrib.auth 모델 권한과 연동됩니다. 이 권한은 .queryset 속성이 있거나 get_queryset() 메서드가 있는 뷰에만 적용해야 합니다. 사용자가 인증되고 관련 모델 권한이 부여된 경우에만 권한이 허용됩니다. 적절한 모델은 get_queryset().model 또는 queryset.model을 통해 확인됩니다.
add 권한을 가지고 있어야 합니다.change 권한을 가지고 있어야 합니다.delete 권한을 가지고 있어야 합니다.기본 동작은 커스텀 모델 권한을 지원하도록 재정의할 수도 있습니다. 예를 들어, GET 요청에 대한 모델 권한을 포함하고 싶을 수 있습니다.
커스텀 모델 권한을 사용하려면 DjangoModelPermissions를 재정의하고 .perms_map 속성을 설정해야 합니다. 자세한 내용은 소스 코드를 참조하세요.
DjangoModelPermissions와 유사하지만, 인증되지 않은 사용자에게도 API에 대한 읽기 전용 접근을 허용합니다.
이 권한 클래스는 Django의 표준 객체 권한 프레임워크와 연동되어, 모델의 개별 객체에 대한 권한을 허용합니다. 이 권한 클래스를 사용하려면 django-guardian과 같은 객체 수준 권한을 지원하는 권한 백엔드도 추가해야 합니다.
DjangoModelPermissions와 마찬가지로, 이 권한은 .queryset 속성이 있거나 get_queryset() 메서드가 있는 뷰에만 적용해야 합니다. 사용자가 인증되고 객체에 대한 관련 권한과 모델 권한이 부여된 경우에만 권한이 허용됩니다.
add 권한을 가지고 있어야 합니다.change 권한을 가지고 있어야 합니다.delete 권한을 가지고 있어야 합니다.DjangoObjectPermissions는 django-guardian 패키지를 필요로 하지 않으며, 다른 객체 수준 백엔드도 동일하게 잘 지원합니다.
DjangoModelPermissions와 마찬가지로, 커스텀 모델 권한을 사용하려면 DjangoObjectPermissions를 재정의하고 .perms_map 속성을 설정해야 합니다. 자세한 내용은 소스 코드를 참조하세요.
참고: GET, HEAD, OPTIONS 요청에 대해 객체 수준의 보기 권한이 필요하고, django-guardian을 객체 수준 권한 백엔드로 사용 중이라면, djangorestframework-guardian2 패키지에서 제공하는 DjangoObjectPermissionsFilter 클래스를 사용하는 것이 좋습니다. 이 클래스는 리스트 엔드포인트가 사용자에게 적절한 보기 권한이 부여된 객체만 반환하도록 보장합니다.
커스텀 권한을 구현하려면 BasePermission을 상속받고 다음 두 메서드 중 하나 또는 둘 다 구현해야 합니다:
.has_permission(self, request, view) .has_object_permission(self, request, view, obj)이 메서드는 요청이 허용되어야 할 경우 True를 반환하고, 그렇지 않으면 False를 반환해야 합니다.
읽기 전용 작업과 쓰기 작업을 구분할 필요가 있다면, SAFE_METHODS 상수를 사용하여 요청 메서드를 확인해야 합니다. SAFE_METHODS는 'GET', 'OPTIONS', 'HEAD'를 포함하는 튜플입니다. 예시:
if request.method in permissions.SAFE_METHODS:
# 읽기 전용 요청에 대한 권한 확인
else:
# 쓰기 요청에 대한 권한 확인
참고: 뷰 수준의 has_permission 검사를 통과한 후에만 인스턴스 수준의 has_object_permission 메서드가 호출됩니다. 또한, 인스턴스 수준의 검사가 실행되려면 뷰 코드에서 명시적으로 .check_object_permissions(request, obj)를 호출해야 합니다. 제네릭 뷰를 사용하면 이 작업은 기본적으로 처리되며, 함수 기반 뷰는 객체 권한을 명시적으로 검사해야 하며, 실패 시 PermissionDenied를 발생시킵니다.
커스텀 권한이 실패하면 PermissionDenied 예외가 발생합니다. 예외와 관련된 에러 메시지를 변경하려면, 커스텀 권한에 직접 message 속성을 구현해야 합니다. 그렇지 않으면 PermissionDenied의 default_detail 속성이 사용됩니다. 또한, 예외와 관련된 코드 식별자를 변경하려면, 커스텀 권한에 직접 code 속성을 구현해야 하며, 그렇지 않으면 PermissionDenied의 default_code 속성이 사용됩니다.
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
message = '고객 추가가 허용되지 않습니다.'
def has_permission(self, request, view):
...
다음은 요청의 IP 주소를 차단 목록과 비교하여, 차단된 IP가 있을 경우 요청을 거부하는 권한 클래스의 예입니다.
from rest_framework import permissions
class BlocklistPermission(permissions.BasePermission):
"""
차단된 IP에 대한 전역 권한 검사.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
글로벌 권한뿐만 아니라 특정 객체 인스턴스에 영향을 미치는 작업에만 실행되는 객체 수준 권한도 만들 수 있습니다. 예를 들어:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
객체 소유자만 해당 객체를 수정할 수 있는 객체 수준 권한.
모델 인스턴스에 `owner` 속성이 있다고 가정.
"""
def has_object_permission(self, request, view, obj):
# 읽기 권한은 모든 요청에 허용되므로,
# GET, HEAD 또는 OPTIONS 요청은 항상 허용합니다.
if request.method in permissions.SAFE_METHODS:
return True
# 인스턴스는 `owner`라는 속성을 가져야 합니다.
return obj.owner == request.user
제네릭 뷰는 적절한 객체 수준 권한을 자동으로 검사하지만, 커스텀 뷰를 작성하는 경우 객체 수준 권한 검사를 직접 수행해야 합니다. 객체 인스턴스를 획득한 후, 뷰에서 self.check_object_permissions(request, obj)를 호출하여 검사할 수 있습니다. 이 호출은 객체 수준 권한 검사가 실패하면 적절한 APIException을 발생시키며, 그렇지 않으면 단순히 반환됩니다.
또한, 제네릭 뷰는 단일 모델 인스턴스를 검색하는 뷰에 대해서만 객체 수준 권한을 검사합니다. 목록 뷰에서 객체 수준 필터링이 필요한 경우, 쿼리셋을 별도로 필터링해야 합니다. 필터링에 대한 자세한 내용은 필터링 문서를 참조하세요.
Django REST Framework는 상황에 따라 접근 제한을 사용자 정의할 수 있는 세 가지 방법을 제공합니다. 이들은 각각의 시나리오에서 다르게 적용되며, 다양한 효과와 제한사항을 가지고 있습니다.
get_queryset() 메서드는 현재 액션에 따라 다른 쿼리셋을 적용할 수 있습니다.get_serializer() 메서드는 현재 액션에 따라 다른 직렬화기를 적용할 수 있습니다.아래 표는 접근 제한 방법과 각 액션에 대한 제어 수준을 보여줍니다.
| Action | queryset | permission_classes | serializer_class |
|---|---|---|---|
| list | global | global | object-level* |
| create | no | global | object-level |
| retrieve | global | object-level | object-level |
| update | global | object-level | object-level |
| partial_update | global | object-level | object-level |
| destroy | global | object-level | no |
액션에서 참조 가능:
queryset: no permission_classes: yes serializer_class: no 요청에서 참조 가능:
queryset: no permission_classes: yes serializer_class: yes Serializer 클래스는 나열 작업에서 PermissionDenied 예외를 발생시키지 않아야 하며, 그렇지 않으면 전체 리스트가 반환되지 않을 수 있습니다.
get_() 메서드는 현재 뷰에 접근할 수 있으며 요청 또는 액션에 따라 다른 Serializer 또는 QuerySet 인스턴스를 반환할 수 있습니다.
다음은 이용 가능한 외부 패키지들입니다.
Django REST - Access Policy 패키지는 뷰 세트 또는 함수 기반 뷰에 부착할 수 있는 선언적 정책 클래스를 사용하여 복잡한 접근 규칙을 정의하는 방법을 제공합니다. 이 정책들은 AWS의 Identity & Access Management 정책과 유사한 형식의 JSON으로 정의됩니다.
Composed Permissions 패키지는 작은 재사용 가능한 구성 요소들을 사용하여 논리 연산자를 통해 복잡하고 다중 깊이의 권한 객체를 정의하는 간단한 방법을 제공합니다.
REST Condition 패키지는 복잡한 권한을 쉽게 구축할 수 있도록 도와주는 또 다른 확장 기능입니다. 이 확장은 논리 연산자를 사용하여 권한을 결합할 수 있도록 합니다.
DRY Rest Permissions 패키지는 기본 및 사용자 정의 액션에 대해 서로 다른 권한을 정의할 수 있는 기능을 제공합니다. 이 패키지는 앱의 데이터 모델에서 정의된 관계로부터 파생된 권한을 가진 앱을 위해 제작되었습니다. 또한 권한 검사를 API의 직렬화기를 통해 클라이언트 앱에 반환할 수 있으며, 기본 및 사용자 정의 나열 액션에 권한을 추가하여 사용자별로 검색되는 데이터를 제한하는 기능도 지원합니다.
Django Rest Framework Roles 패키지는 다양한 유형의 사용자에 대한 API 매개변수를 더 쉽게 설정할 수 있도록 합니다.
Rest Framework Roles는 역할에 기반하여 뷰를 보호하는 기능을 매우 쉽게 제공합니다. 가장 중요한 점은 접근 가능성 로직을 모델과 뷰에서 분리하여 깨끗하고 가독성 높은 방식으로 처리할 수 있다는 것입니다.
Django REST Framework API Key 패키지는 권한 클래스, 모델 및 API 키 인증을 추가하기 위한 도우미 기능을 제공합니다. 이 기능은 사용자 계정이 없는 내부 또는 서드파티 백엔드 및 서비스(즉, 기계)를 인증하는 데 사용될 수 있습니다. API 키는 Django의 비밀번호 해시 인프라를 사용하여 안전하게 저장되며, Django 관리자에서 언제든지 조회, 편집 및 철회할 수 있습니다.
Django Rest Framework Role Filters 패키지는 다양한 유형의 역할에 대해 간단한 필터링을 제공합니다.
Django Rest Framework PSQ 패키지는 permission_classes, serializer_class 및 queryset을 권한 기반 규칙에 따라 의존적으로 설정할 수 있는 기능을 제공합니다.