直接s3 boto3文件上传:访问被拒绝

时间:2018-02-17 05:46:49

标签: amazon-s3 flask boto3

我正在尝试使用我的react本机应用程序通过flask服务器直接将视频上传到s3。我正在关注heroku的guide

React Native

postVideo({className, path}) {
  console.log(`posting ${className} video at ${path}`);

  const vidName = path.substring(path.indexOf('/video_')+1);
  return fetch(SERVER+'/sign_s3?file_name='+vidName+'&file_type=video/mp4', {
    method: 'GET',
  })
  .then((response) => {
    response.json().then((responseText)=> {
      this.uploadVideo({ uri: path, name: vidName, type: 'video/mp4' }, responseText.data, responseText.url);
    })
  })
  .catch((error) => {
    console.error(error);
  });
}

uploadVideo(file, s3Data, url) {
  let form = new FormData();
  for(key in s3Data.fields) {
    form.append(key, s3Data.fields[key]);
  }
  console.log(s3Data);
  form.append('file', file);
  return fetch(url, {
    method: 'PUT',
    body: form,
  })
  .then((response) => {
    console.log(response);
  })
  .catch((error) => {
    console.error(error);
  });
}

Flask服务器(环境变量存储在.env文件中并加载)

from flask import Flask, request, jsonify
import os, boto3

app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

@app.route("/sign_s3")
def sign_s3():
    S3_BUCKET = os.environ.get('S3_BUCKET')

    file_name = request.args.get('file_name')
    file_type = request.args.get('file_type')

    s3 = boto3.client('s3')

    presigned_post = s3.generate_presigned_post(
        Bucket = S3_BUCKET,
        Key = file_name,
        Fields = {"acl": "public-read", "Content-Type": file_type},
        Conditions = [
          {"acl": "public-read"},
          {"Content-Type": file_type}
        ],
        ExpiresIn = 3600
    )

    return jsonify({
        'data': presigned_post,
        'url': 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, file_name)
    }) 

if __name__ == "__main__":
    app.run(host='0.0.0.0')

我设置了一个对s3具有完全访问权限的用户(它也没有使用root凭据) 用户政策(完全访问s3)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "*"
        }
    ]
}

CORS已经设置为

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

错误

<Error>
    <Code>
        AccessDenied
    </Code>
    <Message>
        Access Denied
    </Message>
    <RequestId>
        3399C78F3BD59FAF
    </RequestId>
    <HostId>
        mTgI5xc/iz1z69NRanZ3VfAizg6PPf0s2AdC3nE1nMqDfJYlo2trMMRUmCZMusY1hJ0xBIW21Aw=
    </HostId>
</Error>

如果我将存储桶设置为可公开访问,则上传有效,这让我觉得签名过程一定有问题(因为我也确定我给了用户足够的权限来访问存储区?)

1 个答案:

答案 0 :(得分:1)

我最近也遇到了这个问题。对我来说,在将两个ACL设置都从“公开阅读”更改为“私有”后,它起作用了。