当我通过ajax调用它时,Django Rest框架用AnonymousUser替换我当前经过身份验证的用户?

use*_*774 7 javascript python django django-rest-framework

我正在尝试通过简单的RESTful api和Javascript向Django管理页面添加一些交互式内容.应该很简单,但是我面临一个奇怪的问题,我的每一个请求都来自javascript返回403授权错误.请注意,这仅适用于js.我可以从浏览器中轻轻点击并完成所有基本的CRUD工作.

代码非常基础.

使用Javascript

$.ajax({
    xhrFields: {withCredentials: true},
    type: 'PATCH',
    url: 'path/to/my/endpoint,
    data: {
        aParam: someValue,
        'csrfmiddlewaretoken': getCookie('csrftoken')
    },
    success: doSomething,
    error: doSomething
});
Run Code Online (Sandbox Code Playgroud)

蟒蛇

class MyObjectDetail(RetrieveUpdateDestroyAPIView):
  queryset = MyObject.objects.all()
  serializer_class = MyObjectSerializer

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

我最初怀疑会话ID没有被发送,因此这就是为什么一切都因为权限而失败的原因.但是,会话cookie确实是在ajax POST中发送的,并由Django中间件获取.Django没有任何问题拉我的管理会话.但是,(在经过大量调试之后)我已经将用户重写跟踪到dispatchDjango Rest Framework中的一个方法 - 特别是调用self.initialize_request.在该调用返回之后,我的管理员用户将被替换为其余的一个框架AnonymouseUser.

我完全迷失了.我用调试器花了大约2个小时,但仍然不明白我的用户被换出的原因.以前有人遇到过这个吗?我只是做错了吗?

Kev*_*own 1

403 错误的正文应该包含一条友好的消息,解释问题所在,我认为在这种情况下,您会发现该消息抱怨缺少 CSRF 令牌。

注意,这只适用于js。我可以很好地从浏览器中访问 URL 并执行所有基本的 CRUD 操作。

JS 和浏览器之间只有几处不同,并且它们都不是由 Django REST 框架直接导致的。您可能遇到的问题是 AJAX 请求中如何处理 CSRF:CSRF 令牌应该通过 header 传入。现在这意味着将你的 JavaScript 更改为

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

function addCsrfToken (xhr, settings) {
    if (!csrfSafeMethod(settings.type)) {
        xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
}

$.ajax({
    xhrFields: {withCredentials: true},
    type: 'PATCH',
    url: 'path/to/my/endpoint',
    data: {
        aParam: someValue
    },
    success: doSomething,
    error: doSomething,
    beforeSend: addCsrfToken
});
Run Code Online (Sandbox Code Playgroud)

请注意,虽然Django 文档建议全局设置此标头,但它明确禁止在跨源请求中发送令牌。看起来(从代码withCredentials中)您正在访问不同域上的 API。

Django 毫无问题地提取我的管理会话。

这很可能是因为在浏览器中点击页面不会触发 CSRF 检查,而可浏览的 API 会为您处理 CSRF。

该调用返回后,我的管理员用户被替换为其余框架的AnonymouseUser.

Django REST框架只在一处处理匿名用户,那就是身份验证失败的时候。因此,虽然您的请求可能通过 Django 进行身份验证,但它可能不会通过 Django REST 框架进行身份验证。