Restful 공부중. permission에 대해선 확실히 알고 가야 할것같아. 따로 포스팅한다.
[Permission]
Permission 체크는 항상 view 의 시작에 하게 되는데. ( 다른코드의 진행 전에 실행된단 이야기다 )
기본적으로 Permission Check는 request.user 와 reuqest.auth 의 정보를 사용해서 인증을 처리한다.
Permission은 사용자가 정해진 클래스 이외의 클래스의 접근을 거부하거나 허용하는데 사용한다.
가장 간단하게 사용하는 방법은 인증된 사용자에게는 Access를 허용하고 인증되지 않은 모든 사용자는 Access를 거부하는방법이다.
이것은 REST 프레임 워크의 IsAuthenticated
에 해당합니다.
IsAuthenticated
보다 조금 덜 엄격한 스타일은 권한 없는(인증 되지 않은)사용자에게 읽기 전용 액세스를 허용하는 IsAuthenticatedOrReadOnly
가 있겠다.
[어떻게 권한을 결정하나?]
REST Framework의 권한은 항상 권한 클래스의 목록으로 정의되는데,
View의 본문이 실행되기 전에 목록의 각 권한이 검사된다.
만약 권한통과에 실패하게 되면 exceptions.PermissionDenied 나 exceptions.NotAuthenticated 의 Exception이 raise 하게되고, View의 본문은 실행되지 않는다.
권한 검사가 실패하면, 403 Forbidden또는 401 Unauthorized 응답이 반환되게 된다.
* 요청이 성공적으로 인증되었지만, 권한이 거부되었습니다. - 403에러가 리턴된다.
* 요청이 성공적으로 인증되지 않고 헤더가 WWW-Authenticate 헤더를 사용하지 않았다. - 403에러가 리턴된다.
* 요청이 성공적으로 인증되지않고 헤더가 WWW-Authenticate 를 사용했다 - 401에러가 리턴된다.
[객체레벨 권한]
Object-level-permission은 사용자가 특정한 객체에 대한 작업을 허용해야 하는지 (일반적으로 model 인스턴스입니다) 에 대한 결정을 하는데 사용되어 진다.
객체 레벨 권한은 .get_object()가 호출 될때, REST 프레임워크의 일반 뷰에 의해 실행됩니다.
사용자가 만약 해당 객체에 권한이 없으면 exceptions.PermissionDenied 가 리턴됩니다.
자신의 View를 작성하고 있고, 오브젝트 레벨 권한을 적용하려는 경우나 일반 View에서 get_object를 오버라이드 하는 경우 오브젝트를 검사한 시점에서 뷰에서 .check_object_permissions(request, obj) 를 호출해야 합니다.
[예제]
def get_object(self):
obj = get_object_or_404(self.get_queryset())
self.check_object_permissions(self.request, obj)
return obj
[권한 정책 설정]
기본 권한 정책을 설정할 수 있는데 DEFAULT_PERMISSION_CLASSES
를 사용해서 기본 권한 정책을 사용 할 수 있습니다.
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
지정하지 않으면 설정은 기본적으로 제한없는 엑세스를 허용합니다.
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)
또한 클래스 기반 APIView 를 사용해서 VIew마다 또는 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)
데코레이터를 사용 할 수도 있습니다.
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)
[API 레퍼런스]
제한되지 않은 엑세스를 허용합니다.
인증되지 않은 사용자에게 권한을 거부하고 그렇지 않으면 허용합니다.
IsAdminUser 권한 클래스는 user.is_staff가 True인 경우를 제외하고 모든 사용자의 권한을 거부합니다.
이 권한은 API에서 익명 사용자에게 읽기 권한만 허용하고, 인증된 사용자에게는 쓰기 읽기권한을 허용하려는 경우에 적합합니다.
[커스텀퍼미션]
BasePermission을 상속받고,
.has_permission(self, request, view)
.has_object_permission(self, request, view, obj)
해당 2가지 함수를 오버라이딩 해야합니다.
요청에 대한 엑세스 권한이 부여되면 메서드는 True를 반환, 그렇지 않으면 False를 반환해야만 합니다.
요청이 읽기 작업인지, 아니면 쓰기 작업인지 알아야 하는경우 SAFE_METHODS 상수와 비교해서 요청방법을 확인해합니다.
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
검사 방법은 has_permission 검사가 통과 되어야지만, has_object_permission이 호출 된다는것을 명심하시기 바랍니다.
테스트가 실패 할 경우 사용자 지정 권한은 PermissionDenied 예외를 발생시킵니다.
예외와 관련된 오류 메세지를 변경하려면 message = '에러메세지' 를 사용하십시오.
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
[예제]
다음은 들어오는 요청의 IP 주소를 블랙리스트와 대조해서 IP가 블랙리스트에 올랐으면 요청을 거부하는 권한클래스의 예입니다.
from rest_framework import permissions
class BlacklistPermission(permissions.BasePermission):
"""
Global permission check for blacklisted IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
return not blacklisted
들어오는 모든 요청 (POST,GET,PUT...) 에 대해 실행되는 전역 권한 뿐만 아니라 특정 개체 인스턴스에 영향을 주는 작업에 대해서만 실행되는 개체수준 사용권한을 만들 수도 있습니다.
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user