第二篇文章Django Rest Framework上的CSRF令牌失败

时间:2017-01-13 18:35:18

标签: django django-rest-framework python-requests

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

"detail":"CSRF Failed: CSRF token missing or incorrect."

我不知道我做错了什么,我查看了请求文档,DRF文档,关闭了身份验证以验证网址并搜索了该主题上的旧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})

first_response(登录):

URL - 'http://127.0.0.1:8000/api-v1/'
Text - {"languages":"http://127.0.0.1:8000/api-v1/languages/","phrases":"http://127.0.0.1:8000/api-v1/phrases/","stats":"http://127.0.0.1:8000/api-v1/stats/"}
Status - <Response [200]>

回复(添加语言):

URL - 'http://127.0.0.1:8000/api-v1/languages/?audio_base=adpifajsdpfijsdp&name=French'
Text - {"detail":"CSRF Failed: CSRF token missing or incorrect."}
Status - <Response [403]>

设置非常基础,因为我刚刚开始这样做:

THIRD_PARTY_APP = [
    'rest_framework.authtoken',
    'rest_framework',
]
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

这是一个非常通用的网址信息

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'))
]

我使用ModelSerializers和ModelViewSets,我没有覆盖任何方法并包含所有字段。

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

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"

2 个答案:

答案 0 :(得分:1)

问题是您的第一个请求会记录用户.Dhango在您登录时旋转令牌:

  

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

     

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

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

最重要的是,requests透明地跟随重定向,并返回最后一个响应。由于第二个响应(可能)不使用令牌,因此不会将其设置为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})

答案 1 :(得分:0)

您可能不会使用带有请求的会话来保留下一个请求的初始响应Cookie。

DRF在http://www.django-rest-framework.org/topics/ajax-csrf-cors/#csrf-protection

向您详细介绍了CSRF如何与DRF协同工作