使用django-pipeline,s3boto和storages的SignatureDoesNotMatch Amazon S3不一致

时间:2012-08-05 22:23:48

标签: python django amazon-s3 boto django-storage

我有两个由django-pipeline编译的文件以及s3boto:master.css和master.js。它们在我的桶中设置为“公共”。但是,当我访问它们时,有时会提供master.css,有时它会使用SignatureDoesNotMatch。与master.js相同。这不会发生在Chrome上。我能错过什么?

编辑:现在也发生在Chrome上。

5 个答案:

答案 0 :(得分:13)

也发生在我身上...... 花了几个小时才找到,但我终于明白了。 事实证明,如果正确的签名是:

ssCNsAOxLf5vA80ldAI3M0CU2%2BW =

然后AWS不接受:

ssCNsAOxLf5vA80ldAI3M0CU2 + W =

唯一的区别是%2B转换为'+'。

S3BotoStorage实际上正确地生成了它,但编码发生在url方法(return unquote(final_url))的最后一行的CachedFilesMixin上。 为了修复它,我派生了一个新的CachedFilesMixin来解除“损坏”(我应该提到我不知道为什么这个unquote首先存在,所以撤消它可能会导致其他问题)

class MyCachedFilesMixin(CachedFilesMixin):
def url(self, *a, **kw):
    s = super(MyCachedFilesMixin, self).url(*a, **kw)
    if isinstance(s, unicode):
        s = s.encode('utf-8', 'ignore')
    scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
    path = urllib.quote(path, '/%')
    qs = urllib.quote_plus(qs, ':&=')
    return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))

我使用的代码here

希望这会有所帮助......

答案 1 :(得分:2)

在使用S3签名的URL下载文件并且python请求HTTP库时,我遇到类似的问题导致SignatureDoesNotMatch错误。

我的问题最终成为了一个糟糕的内容类型。 AWS Authenticating REST Requests上的文档帮助我解决了这个问题,并在Python中提供了示例。

答案 2 :(得分:2)

我一直在努力解决这个问题,我不喜欢弄乱CachedFilesMixin的想法(对我来说似乎有点过分了)。

直到对django平台发出适当的修复,我发现两次引用签名是一个不错的选择。我知道它不漂亮,但它很有效,而且很简单。

所以你只需做这样的事情:

signature = urllib.quote_plus(signature.strip())
signature = urllib.quote_plus(signature.strip())

希望它有所帮助!

答案 3 :(得分:0)

关于Flask的这篇文章是一个很好的资源,可以让你的签名正确:https://devcenter.heroku.com/articles/s3-upload-python

@app.route('/sign_s3/')
def sign_s3():
    AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID')       
    AWS_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
    S3_BUCKET = os.environ.get('S3_BUCKET')

    object_name = request.args.get('s3_object_name')
    mime_type = request.args.get('s3_object_type')

    expires = int(time.time()+10)
    amz_headers = "x-amz-acl:public-read"

    put_request = "PUT\n\n%s\n%d\n%s\n/%s/%s" % (mime_type, expires, amz_headers, S3_BUCKET, object_name)

    signature = base64.encodestring(hmac.new(AWS_SECRET_KEY,put_request, sha).digest())
    signature = urllib.quote_plus(signature.strip())

    url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, object_name)

    return json.dumps({
        'signed_request': '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature),
         'url': url
    })

答案 4 :(得分:0)

对我来说,一种简单的解决方法是生成一个仅包含字母数字字符的新访问密钥(即没有特殊字符,例如AWS有时会添加到密钥的“ /”,“ +”等)。