Reputation: 1125
the title pretty much says it all. I'm trying to authenticate with a token. I am getting information from the django database to my flutter app. I've successfully retrieved my token from the rest_framework and added it to the headers of the rest request. I printed these headers in django which results in
{
'Content-Length': '0',
'Content-Type': 'text/plain',
'User-Agent': 'Dart/2.5 (dart:io)',
'Accept-Encoding': 'gzip',
'Authorization': 'Token 10cf58e1402b8e48c1a455aaff7f7bcf53e24231',
'Host': '192.168.0.110:8000'
}
The result however, is the webpage with a login form and not the rest data that I've requested. What am I missing?
settings.py
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
...
views.py
...
@login_required
@csrf_exempt
def ui_list(request):
print(request.headers)
"""
List all code user_informations, or create a new user_information.
"""
if request.method == "GET":
users = UserInformation.objects.all()
serializer = UserInformationSerializer(users, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == "POST":
data = JSONParser().parse(request)
serializer = UserInformationSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
...
Upvotes: 3
Views: 5898
Reputation: 84
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', ) }
adding rest_framework.authentication.TokenAuthentication worked
Upvotes: 0
Reputation: 714
This login_required
is not rest_framework
s way to authenticate. You need to use permission class for authenticating through your api if that's what you are trying to do.
How I implemented it was, I created a view for login
class LoginView(APIView):
"""Class based view loggin in user and returning Auth Token."""
authentication_classes = [TokenAuthentication]
permission_classes = [AllowAny]
def post(self, request):
"""Check if user exists, return token if it does."""
data = JSONParser().parse(request)
serializer_obj = LoginObjectSerializer(data=data)
if serializer_obj.is_valid():
user = authenticate(username=serializer_obj.data['username'], password=serializer_obj.data['password'])
if not user:
return Response({'error': 'Invalid Credentials'}, status=404)
token, _ = Token.objects.get_or_create(user=user)
return Response({'token': token.key}, status=200)
return JsonResponse(serializer_obj.errors, status=400)
And how I authenticated my APIs was by using rest-framework
's provided permission classes instead of @login_required
.
My settings.py
has
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', )
}
and the permission class I used to secure my views was like this
from rest_framework.permissions import AllowAny, IsAuthenticated
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
But I used like this in class based views. For method based, you can do this as mentioned here
@permission_classes([IsAuthenticated])
The crux of this is, you are trying to use token based authentication but you are not actually using it. Create your own login api,and use it like mentiond in this answer or the answer of @sebastienbarbier.
Upvotes: 4
Reputation: 6832
Your problem come from the use of the decorator @login_required
which is suppose to protect a django view.
Django views and django_rest_framework do not use the same authentication system and so need to be implemented differently.
You can remove @login_required
and implement view.py
as followed :
from rest_framework.authentication import TokenAuthentication
...
@csrf_exempt
def ui_list(request):
print(request.headers)
"""
List all code user_informations, or create a new user_information.
"""
if request.method == "GET":
user_auth_tuple = TokenAuthentication().authenticate(request)
if user_auth_tuple is None:
return HttpResponse(status=401)
else:
(user, token) = user_auth_tuple # here come your user object
users = UserInformation.objects.all()
serializer = UserInformationSerializer(users, many=True)
return JsonResponse(serializer.data, safe=False)
if request.method == "POST":
...
...
But doing this process manually is really time consumming, should not be done this way as DRSF provide lots of options to make this automatic.
What should actually be done is match a django rest framework APIView class to your model and generate a proper entry point using the permission system.
REST framework provides an APIView class, which subclasses Django's View class.
APIView classes are different from regular View classes in the following ways:
- Requests passed to the handler methods will be REST framework's Request instances, not Django's HttpRequest instances.
- Handler methods may return REST framework's Response, instead of Django's HttpResponse. The view will manage content negotiation and setting the correct renderer on the response.
- Any APIException exceptions will be caught and mediated into appropriate responses.
- Incoming requests will be authenticated and appropriate permission and/or throttle checks will be run before dispatching the request to the handler method.
Upvotes: 0