[Django Rest Framework]Authentication & Permission (인증과 권한)

DRF Authentication

Donnis Dev-note
7 min readMar 18, 2020

인증

유입되는 요청을 허용/거부하는 것을 결정하는 것이 아닌 단순히 인증정보로 유저를 식별하는 것

Authentication : 유저 식별
Permissions : 각 요청에 대한 허용/거부
Throttling : 일정 기간 동안에 허용할 최대 요청 횟수

인증 처리 순서

  1. 매 요청 시 APIView의 dispatch(request) 호출
  2. APIView의 initial(request) 호출
  3. APIView의 perform_authentication(request) 호출
  4. request의 user 속성 호출 (rest_framework.request.Request 타입)
  5. request의 authenticate() 호출

session 인증에서는 로그인할 때만 인증을 하고 인증을 한 내역을 세션에 담아 매번 세션 정보를 활용하는데 ,
API에서는 C에서 S로 요청을 보낼 때마다 인증을 합니다. (매번, 인증이 유효한지, token 혹은 username,password을 이용해서)

지원하는 인증의 종류

  • SessionAuthentication
    세션을 통한 인증, APIView에서 디폴트로 지정되어 있습니다.
  • BasicAuthentication
    Basic 인증 헤더를 통한 인증 (예>Authorization : Basic YWxsaWV1…….)
    HTTPie를 통한 요청 : 쉘>http- - auth 유저명:암호- - form POST :8000 필드명1:값1 필드명2:값2
  • TokenAuthentication
    Token 헤더를 통한 인증 (예>Authorization: Token 401f7ac837da……..)
  • RemoteUserAuthentication
    User가 다른 서비스에서 관리될 때, Remote 인증을 합니다.
    Remote-User 헤더를 통한 인증을 수행합니다.

인증과 허가

개체 (정보/코드 등)에 대한 접근을 허용하기 위해서, 인증/식별만으로는 충분하지 않습니다. 추가로 각 개체에 대한 허가가 필요합니다.

DRF의 Permission System

: 현재 요청에 대한 허용/거부를 결정, APIView 단위로 지정이 가능합니다.

  • AllowAny (디폴트 전역 설정) : 인증 여부에 상관없이 뷰 호출을 허용
  • IsAuthenticated : 인증된 요청에 한해서 뷰 호출 허용 (로그인이 되어있어야만 접근 허용)
  • IsAdminUser : Staff 인증 요청에 한해서 뷰 호출 허용
  • IsAuthenticatedOrReadOnly : 비인증 요청에게는 읽기 권한만 허용 (로그인이 되어 있지않아도 조회는 가능)
  • DjangoModelPermissons : 인증된 요청에 한하여 뷰 호출 허용, 추가로 장고 모델단위 Permissions 체크
  • DjangoModelPermissionsOrAnonReadOnly : DjangoModelPermissions와 유사, 비인증 요청에게는 읽기만 허용
  • DjangoObjectPermissons : 비인증 요청은 거부, 인증된 요청은 Object에 대한 권한 체크 수행

permission_classes 지정 Example

APIView 에서의 지정

from rest_framework.permissions import IsAuthenticatedclass ExampleView(APIView):
permissions_classes = [IsAuthenticated]

def get(self, request, format=None):
content = {'status' : 'request was permitted'}
return Response(content)

@api_view 에서의 지정

from rest_framework.decorators import permission_classes@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None)
content = {'status' : 'request was permitted'}
returnn Response(content)

Default 전역 설정

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

settings.py에 위의 코드를 작성해주시면 Permission 값이 전역으로 설정됩니다.

커스텀 Permission

모든 Permission 클래스는 다음 2가지 함수를 선택적으로 구현합니다.

  • has_permission(request, view)
    - APIView 접근시, 체크.
    - 거의 모든 Permission 클래스에서 구현되며 로직에 따라 True/False 반환
  • has_object_permission(request, view, obj)
    - APIView의 get_object 함수를 통해 object 획득 시에 체크.
    - 브라우저를 통한 API 접근에서 CREATE/UPDATE Form 노출 시 체크
    DjangoObjectPermissions에서 구현하며 로직에 따라 True/False 반환

DRF의 Permissions 코드 살펴보기

SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')class AllowAny(BasePermission):
def has_permission(self, request, view):
return True
class IsAuthenticated(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated
class IsAdminUser(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_staff

포스팅 작성자가 아니라면 읽기 권한만 부여
(모델에 author 필드가 있다고 가정)

class IsAuthorOrReadOnly(permissions.BasePermission):
# 인증된 유저에 한해, 목록조회/포스팅등록 허용
def has_permission(self, request, view):
return request.user.is_authenticated

# 작성자에 한해 레코드에 대한 수정/삭제 허용
def has_object_permission(self, request, view, obj):
# 조회 요청(GET, HEAD, OPTIONS) 에 대해 인증여부 상관없이 허용
if request.method in permissions.SAFE_METHODS:
return True
# PUT, DELETE 요청에 대해 작성자일 경우 요청 허용
return obj.author == request.user

포스팅 작성자에게 수정권한만 부여하고 삭제는 superuser만

class IsAuthorUpdateOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
return request.user.is_authenticated

def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
if request.method == 'DELETE':
return request.user.is_superuser # 또는 .is_staff
return obj.author == request.user

--

--