每当我通过 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
的调用。在该调用返回后,我的管理员用户被替换为其余框架的 AnonymouseUser
s 之一。
我完全迷路了。我花了大约 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 函数