Django 给出“CSRF 令牌丢失或不正确”。即使在 POST 调用中传递它之后也会出错

Posted

技术标签:

【中文标题】Django 给出“CSRF 令牌丢失或不正确”。即使在 POST 调用中传递它之后也会出错【英文标题】:Django gives 'CSRF token missing or incorrect.' error even after passing it in the POST call 【发布时间】:2019-01-05 22:22:01 【问题描述】:

我有一个 django 应用程序可以成功注册和登录用户。但是我无法注销用户。

在前端,我有一个包含电源按钮图标的网页,点击该图标会触发注销请求。

我在前端使用 Angular js

index.html

<div class="col-xs-2">
     <span style="opacity: 0.5;font-family: FontAwesome;font-size: 14px;color:#838F98;text-align:center;cursor:pointer" ng-click="logout()">
               <i class="fa fa-power-off" aria-hidden="true"></i>
     </span>
</div>

这里我使用ngclick 来调用我的index.js

中定义的logout() 函数

index.js

$scope.logout = function() 
       var url = '/logout';
       var toSend = 
          csrfmiddlewaretoken: ' csrf_token '
     
   $http(
      method: 'POST',
      url: url,
      data: toSend,
   ).then(function(response) 
     response.data;
   )
  ;

这个函数调用我在 urls.py

中定义了一个auth views/logout url

urls.py

from django.contrib.auth.views import login, logout

url(r'^logout$', logout, 'template_name': 'login.html'),

但是当我点击网页上的电源图标时,我得到一个403 Forbidden 错误。它说CSRF verification failed. Request aborted。但是我在javascript POST 调用中传递了csrf 令牌。

我做错了什么?

【问题讨论】:

不是 csrf_token 一个 &lt;input type="hidden"...&gt; 项目,所以现在你传递的不仅仅是令牌。 @WillemVanOnsem 哦,好的,那么正确的方法是什么?以下解决方案对我不起作用。 【参考方案1】:

确保将 csrf 令牌添加到配置模块中的 http 请求标头中,如下所示。

function config($httpProvider) 
    // state provider code

    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';

还要检查您的 django 设置是否有:

CSRF_COOKIE_HTTPONLY=True

CSRF_COOKIE_HTTPONLY 默认为 False,但当为 True 时,客户端 JavaScript 将无法访问 CSRF cookie。阅读更多关于这个here

【讨论】:

【参考方案2】:

当我收到这些错误时,是因为 csrf 令牌不在 html 表单中,这是一个 Django 模板标签,将其添加到您的 html 模板中,然后通过 JavaScript 获取实际令牌以将其与 angular 一起使用 令牌将被隐藏,因此请使用浏览器检查 html 以确认它是否有效,您设置它的方式将不起作用,因为您传递的是模板标签的字符串,Django 应该执行该标签在您可以使用 JavaScript 从您的 html 标记中捕获它之前的 html,然后您可以将其发布到您的视图中

<div class="col-xs-2">
 csrf_token 
     <span style="opacity: 0.5;font-family: FontAwesome;font-size: 14px;color:#838F98;text-align:center;cursor:pointer" ng-click="logout()">
               <i class="fa fa-power-off" aria-hidden="true"></i>
     </span>
</div>

【讨论】:

抱歉,这仍然不能解决问题【参考方案3】:

您可以在 jquery 中创建一个函数来将 CSRF 令牌保存为 cookie,而不是在每次 AJAX 调用时传递 CSRF 令牌(这似乎是一个令人头疼的问题并添加到传递的数据数组中)。

请参阅docs。

创建一个文件“csrf_ajax.js”(或您选择的其他内容)将其粘贴到其中。

function getCookie(name) 
var cookieValue = null;
if (document.cookie && document.cookie !== '') 
    var cookies = document.cookie.split(';');
    for (var i = 0; i < cookies.length; i++) 
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === (name + '=')) 
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
        
    

return cookieValue;


var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) 
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));

$.ajaxSetup(
    beforeSend: function (xhr, settings) 
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) 
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        
    
);

使用静态文件或相对引用加载脚本

现在您可以通过 POST 请求进行 AJAX 调用,而无需担心 CSRF 令牌。

希望这对您有所帮助。干杯

荣誉:)

【讨论】:

【参考方案4】:

你可以试试这个:

第一步:添加 django-cors-headers

setting.py
-----------
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'X-CSRFToken'
)

在视图中添加装饰器

view.py
-------
from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def post(request):
    ## your logic

AngularJS 客户端(将令牌添加到请求标头)

$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;

你可以关注这个link

【讨论】:

以上是关于Django 给出“CSRF 令牌丢失或不正确”。即使在 POST 调用中传递它之后也会出错的主要内容,如果未能解决你的问题,请参考以下文章

Django --CSRF 令牌丢失或不正确

Django - CSRF 令牌丢失或不正确

Django:CSRF 令牌丢失或不正确。 / 避免 % csrf_token %

CSRF 令牌丢失或不正确。 Django + AngularJS

Django - 403 禁止。 CSRF 令牌丢失或不正确

Django 表单中的 CSRF 令牌丢失或不正确