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

Posted

技术标签:

【中文标题】每当我通过 ajax 调用它时,Django Rest 框架会用 AnonymousUser 替换我当前经过身份验证的用户吗?【英文标题】:Django Rest framework replacing my currently authenticated user with AnonymousUser whenever I call it via ajax? 【发布时间】:2015-07-21 07:34:27 【问题描述】:

我正在尝试通过简单的 RESTful api 和 javascript 向 Django 管理页面添加一些交互式内容。应该很简单,但我面临一个奇怪的问题,即我从 javascript 发出的每一个请求都返回 403 授权错误。请注意,这仅适用于 js。我可以很好地从浏览器中访问 url 并执行所有基本的 CRUD 操作。

代码非常基础。

Javascript

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

Python

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

  authentication_classes = (SessionAuthentication,)
  permission_classes = (IsAuthenticated,)

我最初怀疑会话 ID 没有被发送,因此这就是由于权限导致一切都失败的原因。但是,会话 cookie 确实在 ajax POST 中发送并由 Django 中间件获取。 Django 毫无问题地拉动我的管理会话。但是,(经过很多次调试)我已经追踪到用户重写到 Django Rest Framework 中的 dispatch 方法——特别是对 self.initialize_request 的调用。在该调用返回后,我的管理员用户被替换为其余框架的 AnonymouseUsers 之一。

我完全迷路了。我花了大约 2 个小时来调试调试器,但仍然不明白为什么我的用户被换掉了。有没有人遇到过这个问题?我只是做错了什么吗?

【问题讨论】:

@KevinBrown 啊,好吧,我觉得自己像个笨蛋!是的,是 CSRF 没有出现在标题中,这让事情变得很糟糕。一旦我把它放在正确的位置,事情就开始表现得如他们应该的那样。非常感谢! 【参考方案1】:

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

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

JS 和浏览器只有几处不同,没有一个是直接由 Django REST 框架引起的。您可能遇到的问题是 AJAX 请求中如何处理 CSRF:the CSRF token should be passed in through a 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
);

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

Django 毫无问题地拉出我的管理会话。

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

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

Django REST framework 只在一个地方处理匿名用户,that's when authentication fails。因此,虽然您的请求可能通过 Django 进行了身份验证,但它可能没有通过 Django REST 框架进行身份验证。

【讨论】:

以上是关于每当我通过 ajax 调用它时,Django Rest 框架会用 AnonymousUser 替换我当前经过身份验证的用户吗?的主要内容,如果未能解决你的问题,请参考以下文章

通过jQuery ajax调用将值列表传递给django视图

django - ajax - 从 jquery/ajax 调用 python 函数

无法将 Ajax GET 调用中的数据值检索到 Django 视图中

JSF 2.0 每页生成多个请求

通过 AJAX 以 JSON 格式发送 Django 表单

如何通过 Ajax 调用更新数据表