【问题标题】:Token authentication in django (rest_framework) not workingdjango(rest_framework)中的令牌身份验证不起作用
【发布时间】:2020-02-25 14:27:51
【问题描述】:

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

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

【问题讨论】:

  • 您应该收到 401 未经授权的访问,所以问题可能出在 url 或视图上,您​​能显示更多代码吗?网点是否适用于 REST 客户端或文档?
  • @sebastienbarbier 我已经添加了views.py的相关代码
  • 我已经按照 django-rest-framework.org 的教程进行操作,但基于类的视图除外

标签: django authentication django-rest-framework http-token-authentication


【解决方案1】:

此login_required 不是rest_framework 的身份验证方式。如果您正在尝试这样做,则需要使用权限类通过您的 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 提供的权限类而不是 @login_required。 我的settings.py 有

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

我用来保护我的视图的权限类是这样的

from rest_framework.permissions import AllowAny, IsAuthenticated

authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]

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

的说明进行操作
@permission_classes([IsAuthenticated])

关键在于,您尝试使用基于令牌的身份验证,但实际上并未使用它。创建您自己的登录 api,并按照此答案或@sebastienbarbier 的答案中提到的方式使用它。

【讨论】:

    【解决方案2】:

    您的问题来自于使用装饰器 @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 提供了很多选项来自动执行此过程。

    基于类的视图

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

    REST framework 提供了一个 APIView 类,它是 Django 的 View 类的子类。

    APIView 类在以下方面与常规 View 类不同:

    • 传递给处理程序方法的请求将是 REST 框架的 Request 实例,而不是 Django 的 HttpRequest 实例。
    • 处理程序方法可能返回 REST 框架的响应,而不是 Django 的 HttpResponse。视图将管理内容协商并在响应中设置正确的渲染器。
    • 任何 APIException 异常都将被捕获并调解为适当的响应。
    • 传入的请求将经过身份验证并获得适当的权限和/或在将请求分派到处理程序方法之前运行节流检查。

    【讨论】:

    • 根据 rest_framework 文档,如果在 http-request 中设置了身份验证标头,request.user 应该包含相关用户。这会让事情变得容易得多。
    • @login_required 不了解 DRF http-request,因此将您的请求视为未经身份验证。 rest_framework 可能引用了它自己的 Request 实例,由 APIView 类提供;)
    猜你喜欢
    • 2021-07-01
    • 2015-12-15
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 2018-11-13
    • 2018-01-01
    • 2013-12-02
    相关资源
    最近更新 更多