[Django Rest Framework]Authentication & Permission (인증과 권한)
DRF Authentication
7 min readMar 18, 2020
인증
유입되는 요청을 허용/거부하는 것을 결정하는 것이 아닌 단순히 인증정보로 유저를 식별하는 것
Authentication : 유저 식별
Permissions : 각 요청에 대한 허용/거부
Throttling : 일정 기간 동안에 허용할 최대 요청 횟수
인증 처리 순서
- 매 요청 시 APIView의 dispatch(request) 호출
- APIView의 initial(request) 호출
- APIView의 perform_authentication(request) 호출
- request의 user 속성 호출 (rest_framework.request.Request 타입)
- 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 Trueclass IsAuthenticated(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticatedclass 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