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

5

当我从本地机器向远程 Django API 进行 POST 请求时,出现 CSRF 令牌缺失或不正确的错误。

我的 AngularJS 设置:

.config(['$httpProvider', function($httpProvider){

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

}]);

但我仍然收到“CSRF token missing or incorrect”错误。

我检查发送的头部,似乎angular没有发送“HTTP_X_CSRFTOKEN”。

但我可以看到cookie csrftoken=something被发送了。

有人知道发生了什么吗?

请求头部

POST /s/login/ HTTP/1.1
Host: server.somewhere.io:8000
Connection: keep-alive
Content-Length: 290
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost/thesocialmarkt/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,pt-BR;q=0.4,pt;q=0.2
Cookie: csrftoken=hiYq1bCNux1mTeQuI4eNgi97qir8pivi; sessionid=1nn1phjab5yd71yfu5k8ghdch2ho6exc

这是一个重复的问题吗?https://dev59.com/SWMl5IYBdhLWcg3wwZIq - Chris Hawkes
1
不,我仍然遇到这个问题。 - Andre Mendes
你的Django Rest Framework设置是什么? - Sourabh Dev
我们没有使用Django Rest Framework,我们的API是在Django内部原生构建的。 - Andre Mendes
2个回答

1

正如@Chris Hawkes所指出的,这是由@Ye Liu提供的stackoverflow答案

由于angular应用程序不是由django提供的,为了让cookie被设置,angular应用程序需要首先向django发出GET请求。

我验证了只要不进行http get请求,csrftoken cookie就不会被设置。因此只有

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

不起作用。您需要首先进行真实或模拟的http get请求到django rest_framework更新:您的评论促使我进一步研究它,请阅读blog,其中提到:

客户端生成的CSRF-TOKENS。让客户端在Cookie和自定义HTTP头中生成并发送相同的唯一秘密值。考虑到网站只允许读/写其自己域名下的Cookie,因此只有真实站点可以在两个标头中发送相同的值。

所以我们先尝试使用这个单一请求。
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;

您正在将$cookies注入到控制器/服务中。

如果它有效,那么编写拦截器可能是一个不错的选择,并且还可以帮助您进行调试。

我确定您使用的是至少1.2版本的AngularJs,请参阅changeset,并在最近的提交中使用以下代码检查csrf的Angular http服务:

var xsrfValue = urlIsSameOrigin(config.url)
            ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
            : undefined;
        if (xsrfValue) {
          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
        }

所以必须发送与cookie中相同的令牌。
进一步分析,请使用浏览器的开发人员工具查看HTTP请求的请求/响应,并分析标头和Cookie。

我正在页面加载时执行一个get请求。因此,我会在响应中获取CSRFTOKEN。正如您可以在上面发布的请求标头中看到的那样,设置了cookie csrftoken = hiYq1bCNux1mTeQuI4eNgi97qir8pivi; 发生的情况是当我尝试进行另一个请求时,django会说我没有发送令牌。我注意到未发送标头HTTP_X_CSRFTOKEN。 - Andre Mendes
谢谢你的帮助。但我猜只要我在本地机器上,它就不会真正起作用。我稍后会将其上传到服务器并进行测试。 - Andre Mendes

0
如果您在AngularJS中使用$http进行ajax请求,并且遇到任何CSRF令牌问题,请使用以下方法:
$http.defaults.xsrfCookieName = 'csrftoken';
$http.defaults.xsrfHeaderName = 'X-CSRFToken';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接