我使用以下代码首先登录我的网站以获取有效的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 标头时,我认为没有任何理由将令牌也包含在帖子有效负载(请求正文(中。