Python/DRF

[DRF] 게시판에 Authentication과 Permission 적용하기

emhaki 2023. 1. 29. 00:06
728x90
반응형
SMALL

게시판을 작성하는데 있어서 유저가 로그인이 되어있는지 아닌지를 구별해줄 필요성이 있다. 익명 게시판이 아닌경우에는 글을 작성하는 사용자가 로그인 상태인지를 확인해야 하는데 이때 사용하는 개념이 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로 설정해주었다.

permission 설정 전 후 / 비로그인 시

위의 사진과 같이 로그인하지 않은 사용자는 글을 작성할 수 있는 권한이 없는 것을 볼 수 있다. 아직 인증이 되지 않았기 때문에 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

 

[D.R.F] 게시판에 Authentication과 Permission 적용하기

안녕하세요 (ง •_•)ง 오늘은 지난 시간에 실습했던 게시판 CRUD에 이어 authentication과 permission에 대해 알아보도록 하겠습니다. 게시판 CRUD 구현에 대한 부분은 아래의 링크를 참고해주세요! [D.R

wisdom-990629.tistory.com

 

728x90
반응형