【问题标题】:python-requests and django - CSRF verification failed. Request abortedpython-requests 和 django - CSRF 验证失败。请求中止
【发布时间】:2013-11-27 20:31:42
【问题描述】:

我有一个 django 服务器来上传文件,当我使用浏览器时,我可以毫无问题地上传文件。

但是如果我使用 python-requests 命令,它会告诉我 CSRF 验证失败。请求中止。 python-requests代码如下:

    # upload via HTTP
    file = {"docfile": open(fullfilename, "rb")}
    s = requests.Session()
    r = s.get(dhost)
    r = s.post(dhost, files=file)

如果我执行我的代码,我会得到代码 403 并且错误 CSRF 验证失败。请求中止。失败原因:

CSRF 令牌丢失或不正确。

但是如果我查看我发送的标头,我已经设置了 cookie:

CaseInsensitiveDict({'Content-Length': u'84169', 
'Accept-Encoding': 'gzip, deflate, compress', 
'Accept': '*/*', 
'User-Agent': 'python-requests/2.0.1 CPython/2.7.3 Linux/3.6.11+', 
'Cookie': 'csrftoken=GOOIsG89i5oMCJO6594algTXooxoUeoL', 
'Content-Type': 'multipart/form-data; boundary=86ada00b4f6c41d5997293cce7a53b6b'})

你能告诉我我应该怎么做才能让它工作吗?

【问题讨论】:

  • 这段代码是否作为 POST 执行?如果是这样,您是否使用表格?您可能需要将 {% csrf_token %} 添加到表单中。

标签: django python-requests django-csrf


【解决方案1】:

实际上一切正常,你只需要了解 csrf 是如何工作的。当您在浏览器中加载页面时,您会在{% csrf_token %} 中获得一个 csrf 令牌,因此当您将数据发送到服务器时,您也会发送 csrf 令牌。

当您使用请求时,您会在“获取”部分获取 cookie,但不会将其与“帖子”一起发送。没有它,你只是发送一个没有令牌的发布请求,这意味着一个 CSRF 验证错误。要解决它,请尝试以下代码:

file = {"docfile": open(fullfilename, "rb")}
s = requests.Session()
r1 = s.get(dhost)
csrf_token = r1.cookies['csrftoken']
r2 = s.post(dhost, files=file, data={'csrfmiddlewaretoken': csrf_token}, headers=dict(Referer=dhost))

如果这只是供您自己使用,您可以使用 csrf_exampt 在该视图上禁用 csrf:

@csrf_exempt
def my_view(request):
   ...whateva...

但请注意,如果您计划启动服务器并将其向公众开放,则不推荐使用此解决方案

【讨论】:

  • 我想稍后将其公开。问题是当我使用 chrome 浏览器时它可以工作,我有选择文件按钮,然后是上传按钮,如果我点击最后一个,文件会上传到我的 django 网络服务器,我可以在我的文件夹中找到它服务器。那么为什么它不能与 python-requests 命令一起使用,或者我应该使用什么其他命令呢?
  • 正如我所解释的,在使用浏览器时,您将 csrf-token 与 post 请求一起发送。在 python-requests 代码中,如果没有“get”部分,您将发送一个返回错误的无令牌请求
  • 我已经更新了我的问题,因为即使我在出现错误 403 之前进行了获取...所以我不介意之前进行获取,但我的问题确实是我无法发布:(。
  • 是的,我真的很惊讶你说它正在使用'get',但我想可能是不同版本的 django 或其他东西......无论如何,问题仍然是相同的 = 你需要要将令牌与您的请求一起发送,请稍候,我将在答案中对其进行编辑,以向您展示如何...
  • 当然,很高兴能提供帮助! =]
【解决方案2】:

如果我使用 python-requests 命令,它会告诉我 CSRF 验证 失败的。但是如果我查看我发送的标头,我已经设置了 cookie:

  'Content-Length': u'84169', 
  'Accept-Encoding': 'gzip, deflate, compress', 
  'Accept': '/', 
  'User-Agent': 'python-requests/2.0.1 CPython/2.7.3 Linux/3.6.11+',
  'Cookie': 'csrftoken=GOOIsG89i5oMCJO6594algTXooxoUeoL',
  'Content-Type': 'multipart/form-data; boundary=86ada00b4f6c41d5997293cce7a53b6b

你必须将两件事发回服务器:

1) csrftoken cookie。

2) 下面的表单名/值对:

"csrfmiddlewaretoken" = "csrf token here"

requests 会话将负责为您返回 cookie,但您必须添加表单名称/值对:

sess = requests.Session()
r = sess.get(get_url)
my_csrf_token = r.cookies['csrftoken']

with open('myfile.txt') as f:
    r = sess.post(
        post_url,
        data = {
            "csrfmiddlewaretoken": my_csrf_token,
        },
        files = {"myfile": f}

)

print r.status_code
print r.text

当你的 django html 模板包含 csrf 标签时:

<form name="myMessage" 
      method="post" 
      class="signin" 
      action="/myapp/process_form/"
      enctype="multipart/form-data">

{% csrf_token %}

csrf tag 被一个隐藏的表单域替换:

<input type="hidden" 
       value="RTpun6OhlRehRRa2nAIcTtFJk5WuWsLg" 
       name="csrfmiddlewaretoken">

隐藏的表单域向服务器发送一个附加的名称/值对以及表单创建的所有其他名称/值对。名称为"csrfmiddlewaretoken",值为 csrf 令牌。 django 检查 cookie 以及表单数据中的名称/值对。

顺便说一句,为了获得一个用于测试目的的 csrf 令牌,您可以向如下所示的视图发出 get 请求:

def myview(request):
    from django.middleware.csrf import get_token
    get_token(request)  #This causes django to set the csrftoken cookie in the response

    return HttpResponse('server received GET request')

【讨论】:

    【解决方案3】:

    这取决于你想要做什么。

    如果你不需要 CSRF 验证,你可以使用 csrf_exempt 装饰器。

    或者您可以创建一个新的 csrf_exempt 视图,仅通过 python-requests 访问。

    【讨论】:

    • 我明白了,但是为什么当我通过浏览器(例如 chrome)上传文件时它可以工作?
    猜你喜欢
    • 2012-12-07
    • 2015-03-08
    • 1970-01-01
    • 2014-02-03
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多