javascriptdjangoauthenticationdjango-rest-frameworkanonymous-users

Django Rest Framework is detecting AnonymousUser on PUT requests


I have this viewset

class OrderItemViewSet(viewsets.ModelViewSet):
  serializer_class = OrderItemSerializer

  def get_queryset(self):
    print('Current User', self.request.user, self.action)
    return OrderItem.objects.filter(order__owner=self.request.user.profile)

take note of the print('Current User', self.request.user) I have used that to identify the root of the problem.

urls.py

router.register('order_items', shopping_api.OrderItemViewSet, 'order_items')

So far so good... But when I make a PUT request;

    const response = await fetch(api.authurl+'/order_items/'+order_item.id+'/', {
      method: 'PUT',
      headers: api.httpHeaders,
      body: JSON.stringify(order_item)
    });

This error shows up

AttributeError: 'AnonymousUser' object has no attribute 'profile'

The print statement identifies these for a GET then a POST request respectively:

[19/Jun/2020 21:03:02] "GET /sellers/3/ HTTP/1.1" 200 196
Current User AD list
[19/Jun/2020 21:03:03] "GET /order_items/ HTTP/1.1" 200 1046
Current User AnonymousUser update

So I have reason to believe that when I make a get request, the authenticated user is detected, but with a PUT it's suddenly Anonymous. I doubt I have to make frontend authentication right? e.g having Authorization with a token in my headers in the request. Since I have that GET request doing fine.

EDIT: adding SellerViewSet:

class SellerViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
  queryset = Seller.objects.all()
  serializer_class = SellerSerializer

Solution

  • DRF authentication scheme uses Django's default session backend for authentication, if you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as PUT, PATCH, POST or DELETE requests(DRF docs)

    IsAuthenticated requires the both the request.user object and the user logged in(is_authenticated).

    class IsAuthenticated(BasePermission):
        """
        Allows access only to authenticated users.
        """
    
        def has_permission(self, request, view):
            return bool(request.user and request.user.is_authenticated)
    

    you need set header X-CSRFToken to request header for next request so that the server knows who you are

     var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
     xhr.setRequestHeader("X-CSRFToken", csrftoken);
    
    // fetch
     headers:{
      'X-CSRFToken': jQuery("input[name=csrfmiddlewaretoken]").val()
    }
    

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