[英]Django Forbidden 403 Error “CSRF token missing or incorrect” when trying to log in when already logged in
所以我使用所有内置的Django,我没有自己的登录视图。
首先,我将描述如何创建导致此错误的方案:
所以有人登录并打开了多个标签,然后他们退出。 最终,其他选项卡将自己定向到帐户/登录页面,或刷新页面或按下链接,这并不重要。 关键是这个人现在有多个选项卡,这些选项卡都在帐户/登录屏幕上,没有人进行身份验证/登录。
那么这个人就可以成功登录其中一个标签。 然后,他们转到其他选项卡之一,这些选项卡仍在帐户/登录页面上(即使已创建会话)。
如果此人尝试以登录的人身份登录,或者实际上是任何人,实际上即使用户名和密码为空并且他们只是单击登录按钮, 403 Error CSRF token missing or incorrect
也会被抛出。
(我希望这是有道理的)
无论如何,我该如何解决这个问题?
这是我的html模板,如果这有帮助:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class='panel panel-primary' style='margin: 0 auto; max-width: 360px;'>
<div class='panel-heading'>
<h3 class='panel-title'>Login</h3>
</div>
<div class='panel-body'>
<form action='{% url 'login' %}' novalidate='novalidate' role='form' method='post'>
{% csrf_token %}
{{ form|crispy }}
<input type='hidden' name='next' value='{{ next }}' />
<div class='form-group' style='margin-bottom: 0;'>
<p>
<small>
By using this site, you agree to our
<a href='{% url 'privacy-policy' %}'>privacy policy</a>
and
<a href="{% url 'terms-of-use' %}">terms of use</a>.
</small>
</p>
<button class='btn btn-primary' type='submit'>Login</button>
</div>
</form>
</div>
</div>
{% endblock %}
编辑:
我还想补充一点,如果我创建相同的场景而不是立即尝试登录,而是我只重新加载一次页面,403错误就不会发生。
我只是希望能够阻止用户在使用网站时遇到错误(当然,直接在搜索栏中输入内容)。 一个想法可能就是当点击登录时它会刷新csrf令牌的方式与页面刷新的方式相同,这是可能的,这是一个好主意吗?
它会发生,因为出于安全原因,每次用户登录时都会更改密钥的值。
{% csrf_token %}
的隐藏输入。 此值在表单呈现时随机且唯一地生成,并在请求完成后进行比较。 因此,请求只能从授权用户的浏览器发送。 没有办法(我知道)攻击者可以获得此令牌并执行Django后端可以接受的恶意请求。 对于未使用HTTP GET,HEAD,OPTIONS或TRACE的所有传入请求,必须存在CSRF cookie,并且'csrfmiddlewaretoken'字段必须存在且正确。 如果不是,则用户将收到403错误。 验证'csrfmiddlewaretoken'字段值时,只将秘密而不是完整令牌与cookie值中的秘密进行比较。 这允许使用不断变化的令牌。 虽然每个请求可以使用自己的令牌,但秘密仍然是所有人共同的。 此检查由CsrfViewMiddleware完成。
更多详情请点击这里
好吧,看来我找到了一个解决方案并没有直接解决错误,但它确实避免了错误发生的情况。 行为有点不同,但它对我来说效果很好,我认为对其他人来说大部分时间都是一样的。
首先,只要用户已经登录,我就会从登录页面重新路由。我通过创建自己的登录视图来完成此操作:
class LoginView(LoginView):
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(request.GET.get("next") or "/")
else:
return super().dispatch(request, *args, **kwargs)
其次,每当窗口变得“聚焦”时(即切换到选项卡),我都会这样做,发送一个简单的ajax请求来检查用户是否经过身份验证,如果是,则会重新加载窗口,从而将它们带到正确的页面。
为此,我将此javascript添加到login.html
页面:
{% block extrascripts %}
{{ block.super }}
<script>
"use strict";
window.onfocus = function () {
$.ajax({
url: "/accounts/status/",
success: function(result, status, xhr) {
if (result.is_authenticated) {
window.location.reload();
}
}
});
};
</script>
{% endblock %}
并添加了这个观点:
@method_decorator(csrf_exempt, name="get")
class StatusView(View):
def get(self, request, *args, **kwargs):
return JsonResponse({"is_authenticated": request.user.is_authenticated})
我当然也更新了URL。
我还要补充一点,如果你不想在已经过身份验证的情况下被重定向远离登录页面,你可以保留该代码并且仍然应该修复错误,考虑到我在重新加载时没有出现错误首先尝试登录之前的页面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.