티스토리 뷰

Django

REST API Authentication & Permissions

nickas 2019. 8. 29. 16:42

Adding information to our model

from django.db import models

from pygments.lexers import get_all_lexers, get_lexer_by_name
from pygments.styles import get_all_styles
from pygments.formatters.html import HtmlFormatter
from pygments import highlight

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])


class Snippet(models.Model):
    owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
    highlighted = models.TextField()

    class Meta:
        ordering = ['created']

    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(Snippet, self).save(*args, **kwargs)

Adding endpoints for our User models

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 relationship이기 때문에, ModelSerializer를 사용할 때 기본적으로 포함되지 않으므로, 명시적으로 정의.

# views.py
class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    
# urls.py
from django.urls import path

from snippets import views

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

Associating Snippets with Users

새로운 Snippet을 생성할 때 생성한 user를 같이 저장.

.perform_create() 메서드를 사용.

class SnippetList(generics.ListCreateAPIView):
    """
    List all code snippets, or create a new snippet
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

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

create() 메서드가 owner 필드를 request 데이터에 추가하여 전송.

 

위의 내용을 반영하기 위해 SnippetSerializer 수정.

class SnippetSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')

    class Meta:
        model = Snippet
        fields = ['id', 'owner', 'title', 'code', 'linenos', 'language', 'style']

source argument는 Django의 template language가 사용되어지는 것과 비슷한 방식으로 사용되어짐.

ReadOnlyField는 deserialized 될 때 모델 인스턴스를 업데이트하기 위해 사용되지 않음. CharField(read_only=True)로도 표현 가능.

 

Adding required permissions to views

class SnippetList(generics.ListCreateAPIView):
    """
    List all code snippets, or create a new snippet
    """
    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):
    """
    Retrieve, update or delete a code snippet.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

Adding login to the Browsable API

# root urls.py
urlpatterns += [
    path('api-auth/', include('rest_framework.urls')),
]

'api-auth' 주소는 원하는 주소로 수정 가능

 

Object level permissions

# permissions.py
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
class SnippetList(generics.ListCreateAPIView):
    """
    List all code snippets, or create a new snippet
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOny]

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


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    """
    Retrieve, update or delete a code snippet.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOny]

Authenticating with the API

기본적으로 SessionAuthenticationBasicAuthentication이 적용됨

아래와 같이 settings.py에 명시적으로 설정도 가능

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
}

http://pygments.org/

 

Welcome! — Pygments

Welcome! This is the home of Pygments. It is a generic syntax highlighter suitable for use in code hosting, forums, wikis or other applications that need to prettify source code. Highlights are: a wide range of over 300 languages and other text formats is

pygments.org

https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/

 

4 - Authentication and permissions - Django REST framework

Currently our API doesn't have any restrictions on who can edit or delete code snippets. We'd like to have some more advanced behavior in order to make sure that: Code snippets are always associated with a creator. Only authenticated users may create snipp

www.django-rest-framework.org

https://www.django-rest-framework.org/api-guide/authentication/

 

Authentication - Django REST framework

 

www.django-rest-framework.org

 

'Django' 카테고리의 다른 글

ViewSets & Routers  (0) 2019.08.29
Relationships & Hyperlinked APIs  (0) 2019.08.29
Rest Framework Views  (0) 2019.08.29
Serializer  (0) 2019.08.29
클래스 필터링, 검색, 정렬의 이해  (0) 2019.08.28
최근에 올라온 글
글 보관함