繁体   English   中英

Django Forbidden 403在登录时尝试登录时出现“CSRF令牌丢失或错误”错误

[英]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令牌的方式与页面刷新的方式相同,这是可能的,这是一个好主意吗?

它会发生,因为出于安全原因,每次用户登录时都会更改密钥的值。

  • 在每个Django表单中,您都有一个名为“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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM