禁止(CSRF令牌丢失或不正确。)CSRF令牌登录成功后

时间:2018-10-24 21:30:06

标签: python django

我使用以下代码首先登录我的网站以获取有效的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

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

1 个答案:

答案 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标头时,我认为没有任何理由将令牌也包含在帖子有效负载(请求正文)中。