[英]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.