게시판을 작성하는데 있어서 유저가 로그인이 되어있는지 아닌지를 구별해줄 필요성이 있다. 익명 게시판이 아닌경우에는 글을 작성하는 사용자가 로그인 상태인지를 확인해야 하는데 이때 사용하는 개념이 authentication과 permission이다.
✅ Authentication
먼저 authentication에 대해 먼저 알아보면 authentication은 인증이라는 뜻으로 특정 서비스를 사용하는 데 있어 사용자의 신원(회원/비회원/관리자 등)을 확인하는 절차를 의미한다. 즉, user의 id와 password를 확인하는 것이라고 생각할 수 있다.
Django의 REST Framework authentication의 종류로는 크게 5가지가 있다.
1. BasicAuthentication
- HTTP 제어 header로 넘긴 id와 password를 base64로 encoding(보안 상의 위협이 있을 수 있음, 테스트에 적절)
2. TokenAuthentication
- 해당 방식은 token으로 인증, 인증 요청을 보낼 시 key 값을 되돌려주는 방식 (client-server 관계에서 사용하기 적절)
3. SessionAuthentication
- 로그인될 때마다 저장되는 session 정보를 통해 인증
4. RemoteAuthentication
- user 정보가 다른 서비스에서 관리될 때 쓰이는 방식
5. CustomAuthentication
- 개발자가 custom하게 authentication을 만들어서 사용할 수도 있음
지금은 실제 서비스를 만드는 것이 아니기 때문에 흔하게 사용되는 BasicAuthentication과 SessionAuthentication 조합으로 연습을 해보고자 한다.
🔎 views.py
from .models import Blog
from .serializer import BlogSerializer
from rest_framework import viewsets
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
# Blog의 목록, detail 보여주기, 수정하기, 삭제하기 모두 가능
class BlogViewSet(viewsets.ModelViewSet):
# authentication 추가
authentication_classes = [BasicAuthentication, SessionAuthentication]
queryset = Blog.objects.all()
serializer_class = BlogSerializer
def perform_create(self, serializer):
serializer.save(user = self.request.user)
우선 SessionAuthentication과 BasticAuthentication을 사용하기 위해 rest_framework.authentication을 import 해준다. 이후 게시글 기능을 구현했던 BlogViewSet의 authentication_classes에 Basic과 Session을 담아준다. 만약에 모든 view에서 동일한 authentication을 사용하고 싶다면 아래와 같이 settings.py에 한 번만 선언해주어도 된다.
🔎 settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
✅ permission
permission은 특정 서비스를 어느 정도로 이용할 수 있는지에 대한 권한을 의미한다. 예를 들어 내가 작성한 글은 나만 수정하고 삭제할 수 있어야 하는데 이런 것들이 permission에 해당하는 것이다.
Django REST Framework에서 제공하는 permission의 종류로는 8가지가 있다.
1. AllowAny: 인증 / 비인증 모두 허용 (default)
2. IsAuthenticated: 인증된 요청에 대해서만 view 호출
3. IsAdminuser: Staff User에 대해서만 요청 허용(User.is Staff가 True여야 함)
4. IsAuthenticatedOrReadOnly: 비인증 요청에 대해서는 읽기만 허용
5. DjangoModelPermissions: 사용자 인증과 관련 모델 권한이 할당된 경우 허용 (django.contrib.auth 모델 permission과 관련 있음)
6. DjangoModelPermissionOrAnonReadonly: DjangoModelPermission과 유사, 비인증 요청에 대해서는 읽기만 허용
7. DjangoObejctPermissions: 모델에 대한 객체 별로 권한이 할당된 경우 허용
8. Custom Permission: 개발자가 custom하게 permission을 만들어서 사용할 수도 있음
현재 구현하고자 하는 권한은 로그인한 사용자만 글을 작성할 수 있고, 비회원은 글을 볼 수만 있어야하기 때문에
IsAuthenticatedOrReadOnly 권한을 사용해보도록 하자.
🔎 views.py
from .models import Blog
from .serializer import BlogSerializer
from rest_framework import viewsets
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticatedOrReadOnly
# Blog의 목록, detail 보여주기, 수정하기, 삭제하기 모두 가능
class BlogViewSet(viewsets.ModelViewSet):
# authentication 추가
authentication_classes = [BasicAuthentication, SessionAuthentication]
# permission 추가
permission_classes = [IsAuthenticatedOrReadOnly]
queryset = Blog.objects.all()
serializer_class = BlogSerializer
def perform_create(self, serializer):
serializer.save(user = self.request.user)
IsAuthenticatedOrReadOnly를 사용하기 위해 permissions를 import 해주었다. 이후 BlogViewSet의 permission_classes를 IsAuthenticatedOrReadOnly로 설정해주었다.
위의 사진과 같이 로그인하지 않은 사용자는 글을 작성할 수 있는 권한이 없는 것을 볼 수 있다. 아직 인증이 되지 않았기 때문에 read-only로만 접근이 가능하다.
하지만 여기까지만 구현한다면 로그인을 했을 경우 다른 사람이 작성한 게시글을 수정, 삭제를 할 수 있게된다. 그렇기 때문에 권한을 부여할 permissions를 추가해주어야 한다. 앞서서 언급했던 custom permission을 사용해보자.
우선 프로젝트 내부에 permissions.py 파일을 생성해준다.
🔎 permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# 읽기 권한 요청이 들어오면 허용
if request.method in permissions.SAFE_METHODS:
return True
# 요청자(request.user)가 객체(Blog)의 user와 동일한지 확인
return obj.user == request.user
IsOwnerOrReadOnly라는 이름의 permission을 하나 만들어준다. 해당 권한은 우선 SAFE_METHOD(GET, HEAD, OPTHIONS)로 요청이 들어온 경우에는 method를 허용을 해주고, 그 외 (PUT,PATCH,DELETE)에는 게시글의 user와 로그인된 user가 동일한 경우에만 권한을 허용해준다.
🔎 views.py
from .models import Blog
from .serializer import BlogSerializer
from rest_framework import viewsets
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from .permissions import IsOwnerOrReadOnly
# Blog의 목록, detail 보여주기, 수정하기, 삭제하기 모두 가능
class BlogViewSet(viewsets.ModelViewSet):
# authentication 추가
authentication_classes = [BasicAuthentication, SessionAuthentication]
# permission 추가
permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
queryset = Blog.objects.all()
serializer_class = BlogSerializer
def perform_create(self, serializer):
serializer.save(user = self.request.user)
이후에 생성한 IsOwnerOrReadOnly 권한을 import 한 후 이를 permission_classes에 추가를 시켜주면 권한을 가진 사용자만 게시글을 수정 삭제할 수 있게 된다.
Reference
'Python > DRF' 카테고리의 다른 글
[DRF] retrieve 메서드와 router 변수 사용하기 (0) | 2023.02.18 |
---|---|
[DRF] DB에 저장된 데이터를 APIview와 ViewSet으로 Response하기 (2) | 2023.02.17 |
[DRF] 게시판 기능(CRUD) 구현하기 (0) | 2023.01.17 |
[DRF] 커스텀 유저 구현하기(회원가입/로그인) (0) | 2023.01.14 |
[DRF] ViewSets으로 CRUD 구현하기 (0) | 2023.01.12 |