我遇到了一个问题,我可以成功登录,但后续任何请求都显示为
"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"
答案 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协同工作