pythondjangodjango-rest-frameworkpermissions

"detail": "Authentication credentials were not provided." django-rest_framaework


I`m making my own pet project, and i need do permissions for users. When user register and create item, only he/she can delete/change item. But when i make a permissions, next login from user account and try to create item, i get error (get method works).

views.py

from .permissions import IsOnwerOrReadOnly

class CreateItemView(APIView):

   serializer_class = CreateItemSerializer
   permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOnwerOrReadOnly]

   def post(self, request):
       serializer = self.serializer_class(data=request.data)
       serializer.is_valid(raise_exception=True)
       serializer.save(owner=self.request.user)
       return Response(_('item created successfully'), status=status.HTTP_201_CREATED)
   
   def get(self, request, pk, format=None):
       item = [item.name for item in CreateItem.object.all()]
       description = [item.description for item in CreateItem.object.all()]
       type_item  = [item.type_item  for item in CreateItem.object.all()]
       price = [item.price  for item in CreateItem.object.all()]
       return Response({'name':item[pk], 'description':description[pk], 
                        'type_item':type_item[pk], 'price':price[pk]}, status=status.HTTP_200_OK)

   def patch(self, request, pk):
       instance = get_object_or_404(CreateItem, id=pk)
       serializer = CreateItemSerializer(instance, data=request.data, partial=True)
       serializer.is_valid(raise_exception=True)
       serializer.save()
       return Response(_("item updated successfully"), status=status.HTTP_200_OK)
   
   def delete(self, request, pk):
       item = CreateItem.object.get(id=pk)
       item.delete()
       return Response(_("item deleted successfully"), status=status.HTTP_204_NO_CONTENT)

permissions.py

from rest_framework import permissions


class IsOnwerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.owner == request.user

urls.py(items_app)

from .views import CreateItemView
from django.urls import path
urlpatterns = [
    path('item-create/', CreateItemView.as_view(), name='item-create'),
    path('item-create/<int:pk>', CreateItemView.as_view(), name='item-create'),
]

urls.py(auth_app)

from django.urls import path
from .views import (RegisterUserView, VerifyUserEmail, LoginUserView, 
PasswordResetRequestView, PasswordResetConfirmView, SetNewPasswordView,
LogoutView)


urlpatterns = [
    path('register/', RegisterUserView.as_view(), name='register'),
    path('verify-email/', VerifyUserEmail.as_view(), name='verify'),
    path('login/', LoginUserView.as_view(), name='login'),
    path('password-reset/', PasswordResetRequestView.as_view(), name='password-reset'),
    path('password-reset-confirm/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name='password-reset-confirm'),
    path('set-new-password/', SetNewPasswordView.as_view(), name='set-new-password'),
    path('logout/', LogoutView.as_view(), name='logout')
]

Auth and items in defferent apps


Solution

  • I don't know what your settings.py is like, but without the code below, authentication_classes do not exist in your View.

    REST_FRAMEWORK = {
        ...
        'DEFAULT_AUTHENTICATION_CLASSES': (
            ...
            'your authentication class path',
        )
        ...
    }
    

    It means that it is difficult to proceed with the permission.

    To proceed with a specific permission, you need to identify a specific user.

    However, if an authentication class does not exist, an authenticated user is also an Anonymous user.

    That's why you need to add authentication_classes to your View first.

    from .permissions import IsOnwerOrReadOnly
    
    class CreateItemView(APIView):
    
       serializer_class = CreateItemSerializer
       permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOnwerOrReadOnly]
       authentication_classes = [yourAuthenticationClass]
    

    And next, if you look at permissions_classes, there are two permission classes set.

    However, as above, the two permission classes do not work when connected to ','

    To implement when both permission classes are allowed or only one permission class is allowed in the DRF Permission class, you can use the bit operator in the permission class.

    from .permissions import IsOnwerOrReadOnly
    
    class CreateItemView(APIView):
    
       serializer_class = CreateItemSerializer
       permission_classes = [permissions.IsAuthenticatedOrReadOnly|IsOnwerOrReadOnly]
       # or(According to the your intention)
       permission_classes = [permissions.IsAuthenticatedOrReadOnly&IsOnwerOrReadOnly]
    

    The DRF Permission class allows bit operations.

    You can refer to this article. If you are curious about permission bit operation, please refer to this source code