django 和 python 请求 - 在 post 请求上得到 403
django and python requests - getting a 403 on a post request
我正在使用 requests
登录我的 Django 站点进行测试(是的,我知道 Django TestClient,但我在这里需要普通的 http)。我可以登录,只要我做 get 请求,一切就OK了。
当我尝试使用 post 时,我从 csrf 中间件收到了 403。我现在已经通过在我看来使用 @crsf_exempt 解决了这个问题,但我更喜欢长期的解决方案。
这是我的代码:
with requests.Session() as ses:
try:
data = {
'username': self.username,
'password': self.password,
}
ses.get(login_url)
try:
csrftoken = ses.cookies["csrftoken"]
except Exception, e:
raise
data.update(csrfmiddlewaretoken=csrftoken)
_login_response = ses.post(login_url, data=data)
logger.info("ses.cookies:%s" % (ses.cookies))
assert 200 <= _login_response.status_code < 300, "_login_response.status_code:%s" % (_login_response.status_code)
response = ses.post(
full_url,
data=data,
)
return self._process_response(response)
登录正常,我可以在这里看到 csrf 令牌。
INFO:tests.helper_fetch:ses.cookies:<RequestsCookieJar[<Cookie csrftoken=TmM97gnNHs4YCgQPzfNztrAWY3KcysAg for localhost.local/>, <Cookie sessionid=kj6wfmta
但是,中间件将 cookie 视为空。
INFO:django.middleware.csrf:request.COOKIES:{}
我已经添加了日志代码:
def process_view(self, request, callback, callback_args, callback_kwargs):
if getattr(request, 'csrf_processing_done', False):
return None
try:
csrf_token = _sanitize_token(
request.COOKIES[settings.CSRF_COOKIE_NAME])
# Use same token next time
request.META['CSRF_COOKIE'] = csrf_token
except KeyError:
# import pdb
# pdb.set_trace()
import logging
logger = logging.getLogger(__name__)
logger.info("request.COOKIES:%s" % (request.COOKIES))
我调用请求 session.post 的方式是否遗漏了什么?我尝试向其中添加 cookie,没有任何区别。但我完全可以理解为什么 crsf 中间件会出错。我以为 cookie 是会话的一部分,那么为什么它们在我的第二个 post 中丢失了?
response = ses.post(
self.res.full_url,
data=data,
cookies=ses.cookies,
)
受 How to send cookies in a post request with the Python Requests library? 启发的此变体也没有导致任何内容传递给 csrf 中间件:
response = ses.post(
self.res.full_url,
data=data,
cookies=dict(csrftoken=csrftoken),
)
对于登录后的后续请求,请尝试将其提供为 header X-CSRFToken
。
以下对我有用:
with requests.Session() as sesssion:
response = session.get(login_url)
response.raise_for_status() # raises HTTPError if: 400 <= status_code < 600
csrf = session.cookies['csrftoken']
data = {
'username': self.username,
'password': self.password,
'csrfmiddlewaretoken': csrf
}
response = session.post(login_url, data=data)
response.raise_for_status()
headers = {'X-CSRFToken': csrf, 'Referer': url}
response = session.post('another_url', data={}, headers=headers)
response.raise_for_status()
return response # At this point we probably made it
文档参考:https://docs.djangoproject.com/en/dev/ref/csrf/#csrf-ajax
您也可以尝试在视图中使用 this decorator,而不是 csrf_exempt
。我试图重现您的问题,这对我也很有效。
from django.views.decorators.csrf import ensure_csrf_cookie`
@ensure_csrf_cookie
def your_login_view(request):
# your view code
我正在使用 requests
登录我的 Django 站点进行测试(是的,我知道 Django TestClient,但我在这里需要普通的 http)。我可以登录,只要我做 get 请求,一切就OK了。
当我尝试使用 post 时,我从 csrf 中间件收到了 403。我现在已经通过在我看来使用 @crsf_exempt 解决了这个问题,但我更喜欢长期的解决方案。
这是我的代码:
with requests.Session() as ses:
try:
data = {
'username': self.username,
'password': self.password,
}
ses.get(login_url)
try:
csrftoken = ses.cookies["csrftoken"]
except Exception, e:
raise
data.update(csrfmiddlewaretoken=csrftoken)
_login_response = ses.post(login_url, data=data)
logger.info("ses.cookies:%s" % (ses.cookies))
assert 200 <= _login_response.status_code < 300, "_login_response.status_code:%s" % (_login_response.status_code)
response = ses.post(
full_url,
data=data,
)
return self._process_response(response)
登录正常,我可以在这里看到 csrf 令牌。
INFO:tests.helper_fetch:ses.cookies:<RequestsCookieJar[<Cookie csrftoken=TmM97gnNHs4YCgQPzfNztrAWY3KcysAg for localhost.local/>, <Cookie sessionid=kj6wfmta
但是,中间件将 cookie 视为空。
INFO:django.middleware.csrf:request.COOKIES:{}
我已经添加了日志代码:
def process_view(self, request, callback, callback_args, callback_kwargs):
if getattr(request, 'csrf_processing_done', False):
return None
try:
csrf_token = _sanitize_token(
request.COOKIES[settings.CSRF_COOKIE_NAME])
# Use same token next time
request.META['CSRF_COOKIE'] = csrf_token
except KeyError:
# import pdb
# pdb.set_trace()
import logging
logger = logging.getLogger(__name__)
logger.info("request.COOKIES:%s" % (request.COOKIES))
我调用请求 session.post 的方式是否遗漏了什么?我尝试向其中添加 cookie,没有任何区别。但我完全可以理解为什么 crsf 中间件会出错。我以为 cookie 是会话的一部分,那么为什么它们在我的第二个 post 中丢失了?
response = ses.post(
self.res.full_url,
data=data,
cookies=ses.cookies,
)
受 How to send cookies in a post request with the Python Requests library? 启发的此变体也没有导致任何内容传递给 csrf 中间件:
response = ses.post(
self.res.full_url,
data=data,
cookies=dict(csrftoken=csrftoken),
)
对于登录后的后续请求,请尝试将其提供为 header X-CSRFToken
。
以下对我有用:
with requests.Session() as sesssion:
response = session.get(login_url)
response.raise_for_status() # raises HTTPError if: 400 <= status_code < 600
csrf = session.cookies['csrftoken']
data = {
'username': self.username,
'password': self.password,
'csrfmiddlewaretoken': csrf
}
response = session.post(login_url, data=data)
response.raise_for_status()
headers = {'X-CSRFToken': csrf, 'Referer': url}
response = session.post('another_url', data={}, headers=headers)
response.raise_for_status()
return response # At this point we probably made it
文档参考:https://docs.djangoproject.com/en/dev/ref/csrf/#csrf-ajax
您也可以尝试在视图中使用 this decorator,而不是 csrf_exempt
。我试图重现您的问题,这对我也很有效。
from django.views.decorators.csrf import ensure_csrf_cookie`
@ensure_csrf_cookie
def your_login_view(request):
# your view code