我使用以下代码首先登录我的网站以获取有效的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
那么,如何正确传递令牌?
答案 0 :(得分:3)
这在Django "Cross Site Request Forgery protection" documentation的最后进行了解释:
为什么用户登录后可能会遇到CSRF验证失败?
出于安全原因,每次用户登录时,CSRF令牌都会轮换 in。任何在登录之前生成表单的页面都会有旧的, 无效的CSRF令牌,需要重新加载。如果 用户在登录后或登录其他用户后使用后退按钮 浏览器标签。
这也适用于cookie。登录后,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标头时,我认为没有任何理由将令牌也包含在帖子有效负载(请求正文)中。