CSRF令牌在第二个post Django Rest框架上失败

CSRF令牌在第二个post Django Rest框架上失败,django,django-rest-framework,python-requests,Django,Django Rest Framework,Python Requests,我有一个问题,我可以成功登录,但任何后续请求显示为 "detail":"CSRF Failed: CSRF token missing or incorrect." 我不知道我做错了什么,我查看了请求文档、DRF文档,关闭了验证url的身份验证,并搜索了关于该主题的旧SO帖子 这是一个基本功能,附带基本信息 def will_fail(): CURRENT_URL = 'http://127.0.0.1:8000/{}' session = requests.Session()

我有一个问题,我可以成功登录,但任何后续请求显示为

"detail":"CSRF Failed: CSRF token missing or incorrect."
我不知道我做错了什么,我查看了请求文档、DRF文档,关闭了验证url的身份验证,并搜索了关于该主题的旧SO帖子

这是一个基本功能,附带基本信息

def will_fail():
    CURRENT_URL = 'http://127.0.0.1:8000/{}'
    session = requests.Session()
    response = session.get(CURRENT_URL.format('api-auth/login/'))
    csrftoken = response.cookies['csrftoken']

    first_response = session.post(CURRENT_URL.format('api-auth/login/'),
                                  data={'username': 'itsme', 'password': 'password'},
                                  headers={'X-CSRFToken': csrftoken})

    response = session.post(CURRENT_URL.format('api-v1/languages/'),
                            params={'name': "French", "audio_base": "adpifajsdpfijsdp"},
                            headers={'X-CSRFToken': csrftoken})
第一次响应(登录):

这里是URL信息,也是非常通用的

from training.views import LanguageViewSet, PhraseViewSet, PhraseStatsViewSet

router = DefaultRouter()
router.register(r'languages', LanguageViewSet)
router.register(r'phrases', PhraseViewSet)
router.register(r'stats', PhraseStatsViewSet)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^api-v1/', include(router.urls, namespace='api'))
]
我使用的是ModelSerializer和ModelViewSet,我没有覆盖任何方法,而是包含所有字段

编辑: 我已经尝试过更新令牌,但它给了我一个关键错误-

Traceback (most recent call last):
  File "C:/Users/Me/PycharmProjects/proj/post_data.py", line 70, in <module>
    will_fail()
  File "C:/Users/Me/PycharmProjects/proj/post_data.py", line 62, in will_fail
    csrftoken = first_response.cookies['csrftoken']
  File "C:\Users\Me\Envs\proj\lib\site-packages\requests\cookies.py", line 329, in __getitem__
    return self._find_no_duplicates(name)
  File "C:\Users\Me\Envs\proj\lib\site-packages\requests\cookies.py", line 400, in _find_no_duplicates
    raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
KeyError: "name='csrftoken', domain=None, path=None"
回溯(最近一次呼叫最后一次):
文件“C:/Users/Me/PycharmProjects/proj/post_data.py”,第70行,在
你会失败吗
文件“C:/Users/Me/PycharmProjects/proj/post_data.py”,第62行,将失败
csrftoken=第一个响应.cookies['csrftoken']
文件“C:\Users\Me\Envs\proj\lib\site packages\requests\cookies.py”,第329行,在\uu getitem中__
返回self.\u查找\u无重复项(名称)
文件“C:\Users\Me\Envs\proj\lib\site packages\requests\cookies.py”,第400行,在“无重复项”中
raise KeyError('name=%r,domain=%r,path=%r%%(name,domain,path))
KeyError:“name='csrftoken',domain=None,path=None”

您可能没有在请求中使用会话,这将保留下一个请求的初始响应cookie


DRF在

上向您详细介绍了CSRF如何与DRF一起工作问题在于您的第一个请求让用户登录。Django在您登录时旋转令牌:

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

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

您在下一个请求中使用的令牌是在轮换之前使用的令牌。您需要在登录请求之后从cookie中获取新令牌

最重要的是,
请求
透明地遵循重定向,并返回最后一个响应。因为第二个响应(可能)不使用令牌,所以它没有设置为cookie。您可以使用
allow_redirects=False
获取第一个请求,然后从该请求获取新令牌。或者,您可以发送一个新的
GET
请求,请求使用响应正文中的令牌的页面,然后令牌也将作为cookie发送

...

first_response = session.post(CURRENT_URL.format('api-auth/login/'),
                              data={'username': 'itsme', 'password': 'password'},
                              headers={'X-CSRFToken': csrftoken},
                              allow_redirects=False)

# Get the new token
newcsrftoken = first_response.cookies['csrftoken']

response = session.post(CURRENT_URL.format('api-v1/languages/'),
                        params={'name': "French", "audio_base": "adpifajsdpfijsdp"},
                        headers={'X-CSRFToken': newcsrftoken})

我不确定我是否理解,我是否使用了错误的会话?我发出get请求以提取csrf令牌,然后将其传递到后续post请求中。
from training.views import LanguageViewSet, PhraseViewSet, PhraseStatsViewSet

router = DefaultRouter()
router.register(r'languages', LanguageViewSet)
router.register(r'phrases', PhraseViewSet)
router.register(r'stats', PhraseStatsViewSet)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^api-v1/', include(router.urls, namespace='api'))
]
Traceback (most recent call last):
  File "C:/Users/Me/PycharmProjects/proj/post_data.py", line 70, in <module>
    will_fail()
  File "C:/Users/Me/PycharmProjects/proj/post_data.py", line 62, in will_fail
    csrftoken = first_response.cookies['csrftoken']
  File "C:\Users\Me\Envs\proj\lib\site-packages\requests\cookies.py", line 329, in __getitem__
    return self._find_no_duplicates(name)
  File "C:\Users\Me\Envs\proj\lib\site-packages\requests\cookies.py", line 400, in _find_no_duplicates
    raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
KeyError: "name='csrftoken', domain=None, path=None"
...

first_response = session.post(CURRENT_URL.format('api-auth/login/'),
                              data={'username': 'itsme', 'password': 'password'},
                              headers={'X-CSRFToken': csrftoken},
                              allow_redirects=False)

# Get the new token
newcsrftoken = first_response.cookies['csrftoken']

response = session.post(CURRENT_URL.format('api-v1/languages/'),
                        params={'name': "French", "audio_base": "adpifajsdpfijsdp"},
                        headers={'X-CSRFToken': newcsrftoken})