I'm looking for some clarification here.
I have build a react app that connects to a Django Rest Framework (DRF). The app is completely private, meaning that no-one who is not authenticated can do anything. For this I have used TokenAuthentication (for now, because I think that SessionAuthentication would be more secure).
I'm struggling to understand this:
I have found a way to get it working: by decoration my view class with @permission_classes((AllowAny, )) it just works fine. But I'm not happy with this.
So, why is this?
In my settings file I have:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', )
}
In the DRF documentation (link) it says:
DELETE requests require the user to have the delete permission on the model.
But, my user is an admin, so why do I need to explicitly add this decorator?
What am I doing wrong? This can't be the best way to do this. And why is it working well without the decorator if I do the request with an external API client (like Postman - I use Paw)??
For a reference, is my simplified view class:
@permission_classes((AllowAny, ))
class ObservationAPIView(APIView):
def delete(self, request, test_id, observation_id, format=None):
# see if my object exists
try:
obs_object_to_delete = Observation.objects.get(pk=observation_id)
test_obj = Test.objects.get(pk=test_id)
except ObjectDoesNotExist:
errormsg = {
'observation id': observation_id,
'test id': test_id,
'message': 'Cannot delete this object. Observation ID or test ID not found.'
}
return Response(errormsg, status=status.HTTP_404_NOT_FOUND)
# it exists, delete it
obs_object_to_delete.delete()
# return the test data (not the deleted object)
serializer = TestSerializer(test_obj, many=False)
return Response(serializer.data)
def patch(self, request, test_id, observation_id, format=None):
# there is also a PATCH function to allow for edits.
# This does work well without the decorator.
Found it! There was no trailing slash in the url pointing to the delete method.
But instead of giving a 404 error or something, DRF responded with an 401 (Unauthorized) error. This made me look for errors in the authorization.
But still being puzzled by this: by setting the @permission_classes((AllowAny, )) decorator, the trailing slash does not seem to be necessary for my frontend to continue after preflight. Without the decorator (ans thus with the right permissions), React does not want to continue after preflight. If you add a trailing slash in the url, it all works fine. So what is going on here? Does the allowAny bypasses CORS? And does CORS require trailing slashes?
If someone is able to explain me this behaviour I would be very grateful.
Thanks for looking everyone!!
Why happening this?
Since you are added the DEFAULT_PERMISSION_CLASSES globally, ( in settings ) DRF will use that in every class based views.
If you want to use extra/custom permission classes for a particular view, you could add it inside the view class with the help of permission_classes attribute as,
class SampleView(APIView):
permission_classes = (MyCustomPermissionClass,)
....
In your case, you need to override the default behaviour for a particular method.
So, How to override default permission classes for a partiluar method in DRF way?
The APIView class a method called get_permissions() which handle this
class SampleView(APIView):
def get_permissions(self):
if self.request.method == 'DELETE':
return [permission() for permission in (AllowAny,)]
return super(SampleView, self).get_permissions()
# your code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With