Backend/Django

Django Tutorial 4: Authentication & Permissions

Say simple 2024. 3. 10. 04:02
728x90
반응형
http -a admin:password123 POST http://127.0.0.1:8000/snippets/ code="print(789)"

{
    "id": 1,
    "owner": "admin",
    "title": "foo",
    "code": "print(789)",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

Snippet 모델 추가 작성

모델에 내용 추가

  • models.py의 Snippet 모델에 작성
  • User와 연결할 uwner ForeignKey와 하이라이트 추가 
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()

import 추가

from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight

save 메서드 추가

  • import 한 메서드들을 이용함
    • lexer 이름
    • Html 포메터
    • 하이라이트
    def save(self, *args, **kwargs):
        """
        Use the `pygments` library to create a highlighted HTML
        representation of the code snippet.
        """
        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
python manage.py createsuperuser

 

유저 모델에 엔드포인트 추가

  • serializers.py에 UserSerializer 추가
  • snippets는 User와 1대 다 매칭 필드로 many=True 옵션을 줌
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']

UserList와 UserDetail을 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

urls.py에 users의 엔드포인트 추가

path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),

Snippets을 Users와 연결

perform_create 를 사용해 Serializer 인스턴스에 user를 전달함

def perform_create(self, serializer):
    serializer.save(owner=self.request.user)

serializers.py에 ReadOnlyField로 owner를 추가

owner = serializers.ReadOnlyField(source='owner.username')

 

views에 권한 추가

아래 import추가

from rest_framework import permissions

views.py의 SnippetList와 SnippetDetail에 permission_classes 추가

permission_classes = [permissions.IsAuthenticatedOrReadOnly]

 

Browsable API에 로그인 추가

urls.py에 아래 import 추가

from django.urls import path, include
  • api-auth 추가
urlpatterns += [
    path('api-auth/', include('rest_framework.urls')),
]

이제 rest_framework 화면에서 로그인 버튼을 볼 수 있으며 스니펫을 생성할 수 있음

 

객체 레벨 권한

  • permissions.py를 만들고 아래 코드를 작성
  • 이제 view에서 api에 커스텀 권한을 추가할 수 있음
from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.owner == request.user

SnippetDetail의 permission_classes를 아래와 같이 수정

permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly]

import도 추가

from snippets.permissions import IsOwnerOrReadOnly

 

API로 인증하기

  • BasePermission 인증 클래스를 추가했기 때문에 아래와 같은 화면을 볼 수 있음
  • 해당 클래스는 SessionAuthentication과 BasicAuthentication을 포함함
http POST http://127.0.0.1:8000/snippets/ code="print(123)"

{
    "detail": "Authentication credentials were not provided."
}

로그인 하고 나면 아래와 같이 생성에 성공하는 것을 볼 수 있음

http -a admin:password123 POST http://127.0.0.1:8000/snippets/ code="print(789)"

{
    "id": 1,
    "owner": "admin",
    "title": "foo",
    "code": "print(789)",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}
728x90
반응형