Wednesday, 22 May 2019

django 38 rest framework token authentication

get from http://127.0.0.1:8000/api/album_list/, response credential not provided

post to http://127.0.0.1:8000/api/api-token-auth/ with login, obtain token

get request to http://127.0.0.1:8000/api/album_list/ with token, server responds with data

send put request to http://127.0.0.1:8000/api/album_detail/38/ to edit chuanshuo's post but with bob's token
server responds permission denied

 post request to http://127.0.0.1:8000/api/api-token-auth/ with chuanshuo's login
obtain chanshuo's token

send put request to http://127.0.0.1:8000/api/album_detail/38/ with chuanshuo's token to edit his own post, successful


#settings

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
                'rest_framework.authentication.TokenAuthentication',
                ),
    'DEFAULT_PERMISSION_CLASSES':(
        'rest_framework.permissions.IsAuthenticated',
    ),
}

-----------------------------------------
#powershell
python manage.py migrate

------------------------------
#music/api/urls

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from music.api import apiview, mixins
from rest_framework.authtoken import views

app_name = 'musicAPI'

urlpatterns = [
    path('album_list/', apiview.AlbumList.as_view(), name='AlbumList'),
    path('album_detail/<int:pk>/', apiview.AlbumDetail.as_view(), name='AlbumDetail'),
    path('album_list_mixin/', mixins.AlbumListMixin.as_view(), name='AlbumListMixin'),
    path('album_detail_mixin/<int:pk>/', mixins.AlbumDetailMixin.as_view(), name='AlbumDetailMixin'),
    path('api-token-auth/', views.obtain_auth_token, name='AuthToken'),
]

urlpatterns = format_suffix_patterns(urlpatterns)

-----------------------------------------------------
#music/api/apiview

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404

class AlbumList(APIView):
    def get(self, request, format=None):
        albums = Album.objects.all()
        serializer = MusicSerializer(albums, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = MusicSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class AlbumDetail(APIView):

    def get_object(self, pk):
        try:
            return Album.objects.get(pk=pk)
        except Album.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = MusicSerializer(album)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        album = self.get_object(pk)

        #only owner can edit
        if album.author != request.user:
            return Response({"detail": "You do not have permission to perform this action."},
                            status= status.HTTP_403_FORBIDDEN)

        serializer = MusicSerializer(album, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        album = self.get_object(pk)

        # only owner can delete
        if album.author != request.user:
            return Response({"detail": "You do not have permission to perform this action."},
                            status=status.HTTP_403_FORBIDDEN)

        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

-----------------------------------------
#music/api/mixins

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework import mixins, generics, permissions
from .permissions import IsOwnerOrReadOnly

class AlbumListMixin(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class AlbumDetailMixin(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

------------------------------------
#music/api/permisions

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.author == request.user

reference:
https://www.youtube.com/watch?v=PFcnQbOfbUU&list=PLbpAWbHbi5rMV3H0S5IDK3cSRC1Jas3VP&index=3
https://stackoverflow.com/questions/39923384/str-object-is-not-callable-django-rest-framework
https://stackoverflow.com/questions/53649252/django-rest-framework-basepermissionmetaclass-object-is-not-iterable
http://chuanshuoge2.blogspot.com/2019/05/django-37-rest-framework-class-based.html
http://chuanshuoge2.blogspot.com/2019/05/django-36-rest-framework-class-based.html

No comments:

Post a Comment