让我解释一下我在做什么?
我的浏览器上打开了两个标签,显示了我的登录页面(简单的用户名和密码形式)。
使用标签1:我登录时提供正确的凭据。工作正常。
使用标签2 :(不刷新)我再次尝试使用相同或不同的凭据登录 这会引发403禁止错误 失败的原因:CSRF令牌丢失或不正确。
我知道,我正在做一些愚蠢的事情,当我已经登录时,我正在尝试登录。
我想防止引发的脏403错误并使进程顺利,因为第二个登录请求应该在有人已经登录或其他不会破坏流程的情况下被忽略。我该怎么做呢?
我正在使用Django == 1.6.2和django-allauth == 0.14.1
答案 0 :(得分:8)
首先是快速的背景知识,因为您可能会觉得有趣:这部分与CSRF令牌有关,部分与会话有关。
CSRF在Django中的工作方式是在模板和会话中镜像相同的令牌 - 这就是Django如何检查传入的表单数据是否与用户的会话相匹配并且不是一个邪恶的注射。
当您从注销登录到登录时,您将为经过身份验证的会话交易未经身份验证的会话,这意味着您将获得一个新会话 - 在会话中使用新的CSRF令牌。该会话在所有标签中共享,即使是已经打开的标签,甚至是Chrome浏览器,每个标签都有单独的进程。
因此,登录选项卡A会为选项卡B提供一个会话cookie,该cookie不再与页面中嵌入的CSRF令牌匹配,因此选项卡B将作为CSRF例外引发。如果您在登录选项卡A后刷新选项卡B(并假设登录用户仍然可以看到登录屏幕),则应该让您再次登录,因为刷新页面的CSRF令牌将再次登录匹配会话中的那个。
在妥善处理此问题方面,我建议您添加一个custom 403 handler view,它可以显示您自己设计的更漂亮的403页,或者 - 如果您认为它可以接受 - 将用户重定向到在其他地方(但我确定只有在你的问题中描述的虚假登录响应时才会发生此重定向)
另一个要说的是:您正在谈论的用例(打开两个标签页)相当渺茫 - 我只是使用自定义403页面使其更漂亮,而不是重定向。
如果您有兴趣,请查看source:
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令牌 - 我还没有检查过)
答案 1 :(得分:-3)
你应该这样做:
def userlogin(request):
if request.method=='POST':
user = request.user
if user.is_authentificated:
return HttpResponceRedirect('some_url')
else:
#your login procedure