禁止(CSRF 令牌缺失或不正确.CSRF 令牌登录成功后



我使用以下代码首先登录我的网站以获取有效的CSRF令牌,然后我想使用该令牌进行API调用,但是失败了。请帮助我..

import requests
LOGIN_URL = 'http://localhost:8000/admin/login/'
client = requests.session()
# Retrieve the CSRF token first
client.get(LOGIN_URL)
csrftoken = client.cookies['csrftoken']
print('token:'+ csrftoken)
login_data = dict(username='xxxx', password='xxxx', csrfmiddlewaretoken=csrftoken)
r1 = client.post(LOGIN_URL, data=login_data, headers=dict(Referer=LOGIN_URL))
print(r1.status_code, r1.reason)
print('token:'+ csrftoken)
API_URL = 'http://localhost:8000/collection/api/job_submit/'
payload = {'csrfmiddlewaretoken': csrftoken, 'value1': 'val', 'value2': 'val'}
r2 = client.post(API_URL, data=payload, headers={'referer': API_URL, 'X-CSRFToken': csrftoken})
print(r2.status_code, r2.reason)

这是我从服务器得到的:

[24/Oct/2018 21:28:59] "GET /admin/login/ HTTP/1.1" 200 1806
[24/Oct/2018 21:28:59] "POST /admin/login/ HTTP/1.1" 302 0
[24/Oct/2018 21:28:59] "GET /accounts/profile/ HTTP/1.1" 404 91
2018-10-24 21:28:59,914 [WARNING] django.security.csrf: Forbidden (CSRF token missing or incorrect.): /collection/api/job_submit/
[24/Oct/2018 21:28:59] "POST /collection/api/job_submit/ HTTP/1.1" 403 1019

那么,如何正确传递令牌?

这在 Django 的"跨站点请求伪造保护"文档的最后进行了解释:

为什么用户在登录后会遇到 CSRF 验证失败?

出于安全原因,CSRF 令牌在用户每次登录时轮换 在。任何在登录之前生成表单的页面都将有一个旧的, 无效的 CSRF 令牌,需要重新加载。如果 用户在登录后使用后退按钮,或者如果他们登录其他 浏览器选项卡。

这也适用于饼干。登录后,django 会向客户端发送一个新的 csrf cookie。这将存储在client.cookies中并替换旧的。django 服务器不保留旧令牌的任何记录,所以这就是为什么你会得到"CSRF 令牌丢失或不正确"响应的原因。

您可以像以前一样从client.cookies['csrftoken']访问新令牌。

r1 = client.post(LOGIN_URL, data=login_data, headers=dict(Referer=LOGIN_URL))
csrftoken = client.cookies['csrftoken']

实际上,您可以直接使用客户端cookie。这将首先避免此错误。请求会在您使用requests.session()时为您跟踪 cookie。

r2 = client.post(
API_URL, 
data=payload, 
headers={'X-CSRFToken': client.cookies['crsftoken']}
)

当您使用 x-csrftoken http 标头时,我认为没有任何理由将令牌也包含在帖子有效负载(请求正文(中。

最新更新