Django Rest Framework - 使用会话和令牌身份验证

dre*_*c4s 9 python django django-rest-framework django-rest-framework-simplejwt

我正在尝试使其正常工作,但不知道这是否可行。它应该这样做。

我开发使用一个Web应用程序Django+ Rest-Framework+ jQuery,我想有一个外部应用程序使用相同的RESTAPI,使用JWT Tokens进行身份验证。

我现在的配置是这样的。

设置.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_RENDERER_CLASS': [
        'rest_framework.renderers.JSONRenderer',
    ]
}

SIMPLE_JWT = {
    'AUTH_HEADER_TYPES': ('Bearer',),
    }
Run Code Online (Sandbox Code Playgroud)

视图.py

class ListFileView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        user = request.user

        if user:

            obj = Foo.objects.filter(owner=user)
            serializer = FooSerializer(obj, many=True)
            data = serializer.data

            return Response(data, status=status.HTTP_200_OK)

        return Response({'detail': 'You have no access to files.'}, status=status.HTTP_400_BAD_REQUEST)
Run Code Online (Sandbox Code Playgroud)

棘手的部分是,当我使用:

permission_classes = (IsAuthenticated,)
Run Code Online (Sandbox Code Playgroud)

我可以ajax从外部应用程序(使用有效JWT令牌)执行调用,但从jQuery应用程序内部调用(使用经过身份验证的用户)失败:

{"detail":"Authentication credentials were not provided."}
Run Code Online (Sandbox Code Playgroud)

另一方面,如果我使用autentication_classes而不是permission_classes

authentication_classes = (SessionAuthentication, BasicAuthentication)
Run Code Online (Sandbox Code Playgroud)

我可以使用从 Web 应用程序内执行 ajax 调用jQuery,但外部调用失败并出现相同的403错误。

我尝试像这样使用两者:

class ListFileView(APIView):
    authentication_classes = (SessionAuthentication, BasicAuthentication)
    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        ...
Run Code Online (Sandbox Code Playgroud)

但外部呼叫也被拒绝。

这两种类型是否可以Auth在同一个class视图中一起工作,还是应该分成两个端点?

编辑

来自应用程序内的示例调用jQuery

<script type="text/javascript">

function loadTblDocs() {
  $("#tbl-docs > tbody").empty();

  $.ajaxSetup({
      headers: { "X-CSRFToken": '{{csrf_token}}' }
    });

  $.ajax({
    type: 'GET',
    contentType: "application/json; charset=utf-8",
    url: "/api/list/",
    dataType: "json",
    success: function (data) {
                console.log(data);
                }
    });
};

</script>
Run Code Online (Sandbox Code Playgroud)

并通过VBA代码外部:

Set web = CreateObject("WinHttp.WinHttpRequest.5.1")
web.Open "GET", "/api/list/", False
web.SetRequestHeader "Authorization", "Bearer <JWT_TOKEN_HERE>"
web.Send
Run Code Online (Sandbox Code Playgroud)

Ozg*_*ali 13

我无法弄清楚您的情况到底发生了什么,因为您共享的 3 个案例中的行为似乎不一致,但将简单地解释如何在 DRF 中确定身份验证和授权,这可能会帮助您弄清楚问题出来了。

您应该能够毫无问题地使用两个身份验证类。使用 DRF,身份验证的工作方式如下:

在每个请求中,DRF 按照定义的顺序检查提供的身份验证类。对于每个类,有 3 种情况:

  1. 如果它可以使用当前类对请求进行身份验证,则 DRF 设置request.user. 从现在开始,这个请求被认证了。
  2. 如果不存在身份验证凭据,DRF 将跳过该类
  3. 如果身份验证凭据存在但无效,例如Authorization标头中的JWT 令牌无效,DRF 会引发异常并返回 403 响应。

DRF 视图通常使用DEFAULT_AUTHENTICATION_CLASSES设置文件中定义的变量,但如果您在视图中提供它们,设置将被覆盖。

当您添加permission_classes到您的视图时,授权开始发挥作用。permission_classes控制对视图的访问,因此当您添加IsAuthenticated到视图的权限类时,如果您尝试在没有经过身份验证的用户的情况下访问该视图,DRF 将拒绝该请求并返回 403 响应。

因此,在您的初始情况下,您的内部 AJAX 请求在这种情况下失败表明您的请求会话中没有经过身份验证的用户数据。我不知道是什么原因造成的。也许您没有在登录视图中更新请求会话(Django 的登录方法应该自动执行此操作)。

在第二种情况下,您permission_classes从视图中删除,因此无论请求中是否存在经过身份验证的用户,视图都将为请求提供服务。所以预计你的内部 AJAX 请求在这里成功,但我不知道为什么你的外部请求在这种情况下失败。

在您的第三种情况下,从您内部 AJAX 请求的角度来看,情况似乎与第一种情况相同,所以我不知道为什么您的内部 AJAX 请求在这种情况下成功,但在第一种情况下却没有。这里的外部请求失败是预期的,因为您将IsAuthenticated权限类添加到视图中,但未包含JWTAuthentication在 authentication_classes 中,因此您的请求无法在此处使用您的 JWT 令牌进行身份验证。