Reputation: 1721
Im using get_queryset, in ListAPIView
I want to check the user's access token, before providing the list, I done the below but the issue is that get_query set does not return a Response, is there a way to return a response, or I should use an alternative :
this my class in the views.py :
class ListProductsOfCategory(generics.ListAPIView):
serializer_class = ProductSerializer
lookup_url_kwarg = 'category_id'
def get_queryset(self):
# I get the token here from the headers
token = self.request.META.get("HTTP_TOKEN", "")
if not token:
return Response(
data={
"message": "no token!"
},
status=status.HTTP_400_BAD_REQUEST
)
if not UserAccess.objects.filter(accessToken=token).exists():
return Response(
data={
"message": "invalid token!"
},
status=status.HTTP_400_BAD_REQUEST
)
category_id = self.kwargs.get(self.lookup_url_kwarg)
return Product.objects.filter(category_id=category_id)
note that everything is working perfect If I removed the token related part.
thanks in advance.
after last update this is the repsonse :
Upvotes: 2
Views: 3307
Reputation: 1601
I'd suggest you to move check token logic into dispatch()
method. It's a better place than get_queryset
. Or even better to write your own authentication class in order to share it between views.
With some fixes (see updated get_queryset()) it can be:
UPDATE
I think you can go with built-in restframework.exceptions.AuthenticationFailed
.
If you are not satisfied with default DRF exceptions you can create your own custom exceptions. For example somewhere in exceptions.py
:
from rest_framework.exceptions import APIException
class MissingTokenException(APIException):
status_code = 400
default_detail = 'Your request does not contain token'
default_code = 'no_token'
class InvalidTokenException(APIException):
status_code = 400
default_detail = 'Your request contain invalid token'
default_code = 'invalid_token'
Then you can use them in views.py
:
from rest_framework import serializers
from .exceptions import MissingTokenException, InvalidTokenException
class ListProductsOfCategory(generics.ListAPIView):
serializer_class = ProductSerializer
lookup_url_kwarg = 'category_id'
def dispatch(self, *args, **kwargs):
token = self.request.META.get("HTTP_TOKEN", "")
if not token:
raise MissingTokenException
if not UserAccess.objects.filter(accessToken=token).exists():
raise InvalidTokenException
return super().dispatch(*args, **kwargs)
def get_queryset(self):
qs = super().get_queryset()
category_id = self.kwargs.get(self.lookup_url_kwarg)
return qs.filter(category_id=category_id)
Upvotes: 6
Reputation: 579
I'm not 100% if I'm getting this right, but I believe you can just use the regular authentication mechanisms that DRF provides. In this particular example, I think this section of the DRF docs should show you how to do it the "DRF" way: Setting Authentication Scheme
If you add the TokenAuthentication scheme to your application, you don't need to verify the token in your get_queryset
method, but you can just use decorators to restrict access for function-based views or permission_classes
for class-based views:
View-based
I guess this is what you'd be most interested in.
class ListProductsOfCategory(generics.ListAPIView):
serializer_class = ProductSerializer
lookup_url_kwarg = 'category_id'
authentication_classes = (TokenAuthentication, ) # Add others if desired
permission_classes = (IsAuthenticated,)
Route-based
If you only want to restrict access for some of your routes (e.g. only post or detail views), then you can write your own permission class. For example, see this question here: How to add django rest framework permissions on specific method only ?
Upvotes: 0