django (rest_framework) 中的令牌身份验证不起作用

Token authentication in django (rest_framework) not working

标题几乎说明了一切。我正在尝试使用令牌进行身份验证。我正在从 django 数据库获取信息到我的 flutter 应用程序。我已成功从 rest_framework 中检索到我的令牌并将其添加到其余请求的 headers 中。我在 django 中打印了这些 headers 结果是

{
  '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'
}

然而,结果是带有登录表单的网页,而不是我请求的其余数据。我错过了什么?

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

您的问题来自于装饰器 @login_required 的使用,它应该保护 django 视图

Django 视图和 django_rest_framework不使用相同的身份验证系统,因此需要以不同的方式实现。

手动验证

您可以删除 @login_required 并按如下方式实施 view.py :

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":
         ...
...

但是手动执行此过程确实很耗时,不应该以这种方式完成,因为 DRSF 提供了很多选项来自动完成此过程。

Class 基于视图

实际应该做的是将 django rest framework APIView class 与您的模型匹配并使用权限系统生成正确的入口点。

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.

login_required 不是 rest_framework 的身份验证方式。您需要使用权限 class 通过您的 api 进行身份验证,如果这是您想要做的。
我是如何实现的,我创建了一个用于登录的视图

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)

我验证 API 的方式是使用 rest-framework 提供的权限 classes 而不是 @login_required。 我的settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated', )
}

我用来保护我的观点的权限class是这样的

from rest_framework.permissions import AllowAny, IsAuthenticated

authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]

但我在基于 class 的视图中使用了这样的方法。对于基于方法,您可以按照here

所述进行操作
@permission_classes([IsAuthenticated])

问题的症结在于,您正在尝试使用基于令牌的身份验证,但实际上并没有使用它。创建您自己的登录名 api,并像此答案或@sebastienbarbier 的答案中提到的那样使用它。