djangoauthenticationdjango-rest-frameworkhttp-token-authentication

Token authentication in django (rest_framework) not working


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)
...

Solution

  • This login_required is not rest_frameworks 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.