簡體   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