带有CORS文件上传的Amazon S3; s3upload.js的例子

时间:2013-08-13 21:38:55

标签: django file-upload amazon-s3 cors

我正在尝试设置一个Django应用程序以允许CORS上传到Amazon S3存储桶 - 运气不错。我一直在Firefox和Chrome上获得403 Forbidden消息,无论是在localhost还是从Web服务器。我已经验证我的签名正确计算(如下所述),我的存储桶策略是允许原始*,允许PUT / POST / GET方法,并允许标题*。我的访问密钥/密钥对是正确的,允许我通过Cyber​​duck等软件访问存储桶。我还能检查什么,或者我如何进一步调试?我觉得我已经探索了所有可能的途径

我正在尝试关注此demo,只是修改编码以匹配此SO question。这允许我的签名匹配this Amazon S3 test file。我的签名生成代码在这里:

s3_bucket_name = settings.S3_BUCKET_NAME
s3_access_key = settings.S3_ACCESS_KEY
s3_secret_key = settings.S3_SECRET_KEY

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

expires = int(time.time()+300)
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_name, object_name)

hashed = hmac.new(s3_secret_key, put_request, sha1)
signature = binascii.b2a_base64(hashed.digest())[:-1]
signature = urllib.quote_plus(signature.strip())

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

signed_request = '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, s3_access_key, expires, signature)

pdb.set_trace()

return HttpResponse(json.dumps({
    'signed_request': signed_request,
     'url': url
  }), mimetype='application/json')

我的上传功能:

function s3_upload(filename) {
filename = filename.split('\\').pop();
var s3upload = new S3Upload({
    file_dom_selector: '#video_file',
    s3_sign_put_url: 'signS3put/',
    s3_object_name: filename,
    onProgress: function(percent, message, publicUrl, file) {
      console.log('Upload progress: ', percent, message);
    },
    onFinishS3Put: function(public_url, file) { 
      console.log('Upload finished: ', public_url);
    },
    onError: function(status, file) {
      console.log('Upload error: ', status);
    }
});
}

我的文件输入按钮:

video_form.append('<input class="input-block-level"' +  
            'autocomplete=off id="video_file" name="video_file"' +  
            'type=file required="required" onchange="' + 
                    'var filename = $(this).val();' + 
                    's3_upload(filename);" />');

在本地开发服务器和远程服务器上都发生了这种情况,因此这不是SO post关于Chrome阻止本地服务器CORS呼叫的说法。

感谢您的提示!

1 个答案:

答案 0 :(得分:5)

所以我解决了这个问题,希望这会帮助其他人(虽然没有其他人似乎有这个问题,所以也许我的设置只是不同)。我的问题原来是s3upload.js库。两件事:

  1. 我想进行authenticated-read,在示例sign_s3视图中设置为public-read。只是在视图中更改它没有帮助 - x-amz-acl:public-read也在函数uploadToS3(第107行)中的s3upload.js中进行了硬编码。因此,您必须更改此选项以匹配您的视图,否则我认为签名编码永远不会匹配CORS请求标头。
  2. 特殊字符=,+和/正在杀了我。在Amazon S3 article的底部提到了它们作为值得注意的事项,因此我确保散列算法取代了它们。问题是,即使我的视图中的哈希算法正确地用转义字符替换这三个字符,s3upload也会解码并将它们重新编码为=,+和/。我在executeOnSignedUrl(第71行)中更改了一行:

      return callback(result.signed_request, result.url);
      //return callback(decodeURIComponent(result.signed_request), result.url);
    
  3. 现在它神奇地起作用了!请注意,这与this SO solution非常相似,只是特定于s3upload.js库。

    作为旁注 - S3似乎也不喜欢键名中的空格(我确实在亚马逊文档中的某处读过,我认为),这是我遇到的另一个问题......