EDIT
因此,经过一番研究后,我发现了以下内容:
Django 不一定会在标头中设置 CSRF 令牌,除非它正在渲染显式具有以下内容的模板:csrf_token
包括模板标签。这意味着您需要请求一个使用 csrf 令牌呈现表单的页面,或者您需要创建一个用以下修饰的令牌请求视图ensure_csrf_cookie
.
由于 csrf 令牌在每个会话中都是唯一的,因此可以创建如下所示的通用令牌设置视图:
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def token_security(request):
return HttpResponse() # json or whatever
然后,任何时候您希望 POST 到 CSRF 保护的端点并且 cookie 中没有 CSRF 令牌,请针对此视图发出 GET,它应该设置 cookie,然后可以将其用于 POST。
原答案如下:
以下内容在我的测试中有效(我使用工厂来创建 User 对象,但您可以手动创建它们):
class TestLoginApi(APITestCase):
def setUp(self):
self.client = APIClient(enforce_csrf_checks=True)
self.path = reverse("registration:login")
self.user = UserFactory()
def tearDown(self):
self.client.logout()
def _get_token(self, url, data):
resp = self.client.get(url)
data['csrfmiddlewaretoken'] = resp.cookies['csrftoken'].value
return data
def test_login(self):
data = {'username': self.user.username,
'password': PASSWORD}
data = self._get_token(self.path, data)
# This should log us in.
# The client should re-use its cookies, but if we're using the
# `requests` library or something, we'd have to re-use cookies manually.
resp = self.client.post(self.path, data=data)
self.assertEqual(resp.status_code, 200)
etc.
如果这一切都是动态完成的,您还必须确保您的视图在 GET 上设置了 cookie,因为根据 Django 文档(请参阅警告) https://docs.djangoproject.com/en/1.8/ref/csrf/#ajax,如果您不从具有以下内容的模板发回,则不会自动设置{% csrf_token %}
set.
如果您需要设置它,看起来像这样(在您的 DRF views.py 中):
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import ensure_csrf_cookie
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
return SomeJson...
最后,对于我的 Django Rest Framework 视图,我必须确保 POST 也受到 csrf 保护(但这看起来不像您遇到的问题):
from django.views.decorators.csrf import csrf_protect
@method_decorator(csrf_protect)
def post(self, request, *args, **kwargs):
return SomeJson...