让我解释一下我在做什么?
我在浏览器上打开了两个标签,显示了我的登录页面(简单的用户名和密码表单).
使用选项卡1:我登录时提供正确的凭据.工作正常.
使用选项卡2 :(不刷新)我再次尝试使用相同或不同的凭据登录,这会引发403禁止错误失败原因:CSRF令牌丢失或不正确.
我知道,我正在做一些愚蠢的事情,当我已经登录时,我正在尝试登录.
我想防止引发的脏403错误并使进程顺利,因为当有人已经登录或其他不会破坏流程时,应该忽略第二个登录请求.我该怎么做呢?
我正在使用Django == 1.6.2和django-allauth == 0.14.1
首先是快速的背景知识,因为您可能会觉得有趣:这部分与CSRF令牌有关,部分与会话有关.
CSRF在Django中的工作方式是在模板和会话中镜像相同的标记 - 这就是Django如何检查传入的表单数据是否与用户的会话匹配,而不是来自某个邪恶的注入.
当您从注销登录到登录时,您正在为经过身份验证的会话进行未经身份验证的会话,这意味着您将获得一个新会话 - 在会话中使用新的CSRF令牌.该会话在所有标签中共享,即使是已经打开的标签,甚至是Chrome浏览器,每个标签都有单独的进程.
因此,登录选项卡A会为选项卡B提供一个会话cookie,该cookie不再与页面中嵌入的CSRF令牌匹配,因此选项卡B将作为CSRF例外引发.如果您在登录选项卡A后刷新选项卡B(并假设登录用户仍然可以看到登录屏幕),则应该让您再次登录,因为刷新页面的CSRF令牌将再次与会议.
在处理这个优雅的方面,我建议你添加一个自定义的403处理程序视图,它可以显示你自己设计的更漂亮的403页面,或者 - 如果你认为它是可接受的 - 将用户重定向到其他地方(但我会检查)只有当你的问题中描述的虚假登录响应时,才会发生此重定向)
另一件要说的是:你正在讨论的用例(两个标签打开)非常小 - 我只是使用自定义403页面使其更漂亮,而不是重定向.
如果您有兴趣,请查看来源:
if SESSION_KEY in request.session: if request.session[SESSION_KEY] != user.pk: # To avoid reusing another user's session, create a new, empty # session if the existing session corresponds to a different # authenticated user. request.session.flush() else: request.session.cycle_key()
当您从未经身份验证的用户开始时,user.pk将无法与经过身份验证的用户的PK相同,因此您将获得一个新会话.
(如果您再次以同一用户身份登录,则会调用cycle_key(),这可能实际上保留了CSRF令牌 - 我还没有检查过)