django和python请求 - 在发布请求时获得403

JL *_*ret 5 django django-csrf python-requests

我正在使用requests登录我的Django网站进行测试(是的,我知道Django TestClient,但我需要简单的http).我可以登录,只要我收到请求,一切都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)
Run Code Online (Sandbox Code Playgroud)

登录工作正常,我可以在这里看到csrf令牌.

 INFO:tests.helper_fetch:ses.cookies:<RequestsCookieJar[<Cookie csrftoken=TmM97gnNHs4YCgQPzfNztrAWY3KcysAg for localhost.local/>, <Cookie sessionid=kj6wfmta
Run Code Online (Sandbox Code Playgroud)

但是,中间件将cookie视为空.

INFO:django.middleware.csrf:request.COOKIES:{}
Run Code Online (Sandbox Code Playgroud)

我已经将日志代码添加到它:

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))
Run Code Online (Sandbox Code Playgroud)

我是否因为我打电话给请求的session.post错过了什么?我尝试添加cookie,没有任何区别.但我完全可以理解为什么crsf中间件会被淘汰出局.我认为cookie是会话的一部分,所以为什么他们在我的第二篇文章中丢失了?

            response = ses.post(
                self.res.full_url,
                data=data,
                cookies=ses.cookies,
                )
Run Code Online (Sandbox Code Playgroud)

这种变化的灵感来自如何使用Python请求库在发布请求中发送cookie?,也没有导致任何传递给csrf中间件:

            response = ses.post(
                self.res.full_url,
                data=data,
                cookies=dict(csrftoken=csrftoken),
                )
Run Code Online (Sandbox Code Playgroud)

fip*_*ips 5

对于登录后的后续请求,请尝试将其作为标头提供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
Run Code Online (Sandbox Code Playgroud)

文档参考:https://docs.djangoproject.com/en/dev/ref/csrf/#csrf-ajax