시작
이번 포스트에서는 DRF(Django Rest Framework) 튜토리얼을 따라 Authentication와 Permissions을 다루는 방법을 알아보겠습니다. 본 포스트는 macOS와 VS Code 환경에서 진행됩니다.
본문
Snippet 모델과 유저 모델 관계 추가
먼저 snippets/models.py
의 Snippet
모델에 새로운 필드를 추가하여 사용자와 연결합니다.
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()
또한 pygments
라이브러리를 사용하여 코드 조각의 HTML 표현을 강조 표시할 수 있는 save
메서드를 정의합니다.
# ...
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
# ...
class Snippet(models.Model):
# ...
def save(self, *args, **kwargs):
"""
`pygments` 라이브러리를 사용하여 강조 표시된 HTML 만들기 코드 조각의 표현.
"""
lexer = get_lexer_by_name(self.language)
linenos = 'table' if self.linenos else False
options = {'title': self.title} if self.title else {}
formatter = HtmlFormatter(style=self.style, linenos=linenos,
full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter)
super().save(*args, **kwargs)
이제 데이터베이스 테이블을 업데이트해야 합니다. 아래 명령어를 실행하여 변경 사항을 반영합니다.
rm -f db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate
마지막으로 superuser
를 생성하여 관리 권한을 가진 사용자를 추가합니다.
python manage.py createsuperuser
유저 모델에 대한 endpoints
를 추가
snippets/serializers.py
에 유저를 위한 serializer
를 추가합니다.
from django.contrib.auth.models import User
# ...
# ...
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
fields = ['id', 'username', 'snippets']
여기서 snippets
은 유저 모델의 reverse
관계이기 때문에 ModelSerializer
클래스를 사용할 때 기본적으로 포함되지 않으므로 이에 대한 명시적 필드로 추가해야 합니다.
그리고 generic class-based views
의 ListAPIView
와 RetrieveAPIView
를 사용하여 snippets/views.py
에 유저 뷰를 추가합니다.
from django.contrib.auth.models import User
from snippets.serializers import UserSerializer
# ...
# ...
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
마지막으로 snippets/urls.py
에 유저 뷰의 URL 패턴을 추가합니다.
# ...
urlpatterns = [
# ...
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
]
# ...
Snippet과 유저 연결
snippet
이 생성될 때 해당 유저 정보가 함께 저장되도록 SnippetList
뷰의 perform_create()
메서드를 재정의합니다.
snippets/views.py
의 SnippetList
view를 수정합니다.
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
이제 Snippet
을 생성할 때 자동으로 현재 요청을 보낸 유저가 owner
필드로 저장됩니다.
Serializer 업데이트
serializers.py
의 SnippetSerializer
를 업데이트하여 유저를 반영합니다.
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source="owner.username")
class Meta:
model = Snippet
fields = ["id", "title", "code", "linenos", "language", "style", "owner"]
여기 ReadOnlyFiled
는 직렬화할 때는 활성화되지만 역직렬화할 때는 비활성화됩니다.
권한 설정 추가
SnippetList
와 SnippetDetail
뷰에 permissions.IsAuthenticatedOrReadOnly
를 추가하여 인증된 사용자만 스니펫을 생성, 수정, 삭제할 수 있게 하고 인증되지 않은 사용자에게는 읽기 권한만 부여합니다.
from django.contrib.auth.models import User
from rest_framework import generics
from rest_framework import permissions
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
# ...
로그인 기능 추가
config/urls.py
에 api-auth
패턴을 추가하여 브라우저에서 로그인 기능을 활성화합니다.
urlpatterns += [
path('api-auth/', include('rest_framework.urls')),
]
API를 사용할 때 로그인하지 않은 상태에서는 로그인 버튼이 제공됩니다.
로그인을 클릭하면 로그인 페이지로 이동하게 됩니다.
Object
기준 권한 설정
snippet
의 소유자만 수정할 수 있도록 권한을 설정하려고 permissions.py
파일을 생성하고 아래 코드를 추가합니다.
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
소유자만 수정할 수 있는 권한을 부여합니다.
"""
def has_object_permission(self, request, view, obj):
# 읽기 권한은 모든 요청에 허용됩니다.
# 따라서 GET, HEAD 또는 OPTIONS 요청은 항상 허용됩니다.
if request.method in permissions.SAFE_METHODS:
return True
# 쓰기 권한은 스니펫의 소유자에게만 허용됩니다.
return obj.owner == request.user
SnippetDetail
뷰에서 이 권한을 적용합니다.
from snippets.permissions import IsOwnerOrReadOnly
# ...
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly]
# ...
마무리
이 포스트에서는 Django Rest Framework를 사용하여 인증과 권한 설정을 추가하는 방법을 살펴보았습니다. 이를 통해 DRF에서 인증과 권한을 설정하는 기본적인 방법을 이해할 수 있었습니다.
참고자료
'Django' 카테고리의 다른 글
DRF Tutorial 6 ViewSets & Routers (0) | 2024.09.14 |
---|---|
DRF Tutorial 5 Relationships & Hyperlinked APIs (0) | 2024.09.14 |
DRF Tutorial 3 Class-based Views (0) | 2024.09.14 |
DRF Tutorial 2 Requests and Responses (0) | 2024.09.11 |
DRF Tutorial 1 Serialization (0) | 2024.09.11 |
댓글