2015-12-18 22 views
6

Tôi đang xây dựng một ứng dụng web bao gồm tính năng tải tệp lên. Mục tiêu của tôi là bắt đầu tải trực tiếp từ người dùng lên một thùng S3. Chiến lược này là ký trước một yêu cầu POST sẽ được gửi dưới dạng biểu mẫu.Tải lên dựa trên trình duyệt AWS S3 của Amazon bằng cách sử dụng POST -

Rào cản là lỗi SignatureDoesNotMatch - theo như tôi có thể nói tôi đã tuân thủ tài liệu và đã khám phá nhiều tùy chọn nhưng vẫn không thể giải quyết được. Tôi có thể tạo các liên kết tải xuống được chỉ định.

Cách tham khảo:

AWS POST documentation

Example

boto3 generate_presigned_post reference

Tạo yêu cầu ký:

def s3_upload_creds(name, user): 
    s3 = boto3.client('s3') 
    key = '${filename}' 
    region = 'us-east-1' 
    date_short = datetime.datetime.utcnow().strftime('%Y%m%d') 
    date_long = datetime.datetime.utcnow().strftime('%Y%m%dT000000Z') 
    fields = { 
     'acl': 'private', 
     'date': date_short, 
     'region': region, 
     'x-amz-algorithm': 'AWS4-HMAC-SHA256', 
     'x-amz-date': date_long 
    } 

    return s3.generate_presigned_post(
     Bucket = 'leasy', 
     Fields = fields, 
     Key = key, 
     Conditions = [ 
      {'acl': 'private'}, 
      {'x-amz-algorithm': 'AWS4-HMAC-SHA256'}, 
      {'x-amz-credential': '/'.join(['AKI--snip--', date_short, region, 's3', 'aws4_request'])}, 
      {'x-amz-date': date_long} 
     ] 
    ) 

hình thức tải lên (dân cư với fields ở trên):

<html> 
    <head> 

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 

    </head> 
    <body> 
    {{ creds }} 
    <form action="{{ creds.url }}" method="post" enctype="multipart/form-data"> 
    Key to upload: 
    <input type="input" name="key" value="${filename}" /><br /> 
    <input type="input" name="acl" value="{{ creds.fields.acl }}" /> 
    <input type="hidden" name="Policy" value="{{ creds.fields.policy }}" /> 
    <input type="text" name="X-Amz-Algorithm" value="{{ creds.fields['x-amz-algorithm'] }}" /> 
    <input type="input" name="X-Amz-Credential" value="{{ creds.fields.AWSAccessKeyId }}/{{ creds.fields.date }}/us-east-1/s3/aws4_request" /> 
    <input type="input" name="X-Amz-Date" value="{{ creds.fields['x-amz-date'] }}" /> 
    <input type="input" name="X-Amz-Signature" value="{{ creds.fields.signature }}" /> 
    File: 
    <input type="file" name="file" /> <br /> 
    <!-- The elements after this will be ignored --> 
    <input type="submit" name="submit" value="Upload to Amazon S3" /> 
    </form> 

</html> 

phần có liên quan của phản ứng:

<Error> 
<Code>SignatureDoesNotMatch</Code> 
<Message> 
The request signature we calculated does not match the signature you provided. Check your key and signing method. 
</Message> 
<AWSAccessKeyId>AKI--snip--</AWSAccessKeyId> 
<StringToSign> 
eyJjb25kaXRpb25zIjogW3siYWNsIjogInByaXZhdGUifSwgeyJ4LWFtei1hbGdvcml0aG0iOiAiQVdTNC1ITUFDLVNIQTI1NiJ9LCB7IngtYW16LWNyZWRlbnRpYWwiOiAiQUtJQUlDVjRNVlBUUlFHU1lLV1EvMjAxNTEyMTgvdXMtZWFzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LCB7IngtYW16LWRhdGUiOiAiMjAxNTEyMThUMDAwMDAwWiJ9LCB7ImJ1Y2tldCI6ICJsZWFzeSJ9LCBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAiIl1dLCAiZXhwaXJhdGlvbiI6ICIyMDE1LTEyLTE4VDA1OjEwOjU2WiJ9 
</StringToSign> 
<SignatureProvided>wDOjsBRc0iIW7JNtz/4GHgfvKaU=</SignatureProvided> 

Base64 decode của StringToSign do lỗi trên:

{u'conditions': [{u'acl': u'private'}, 
       {u'x-amz-algorithm': u'AWS4-HMAC-SHA256'}, 
       {u'x-amz-credential': u'AKI--snip--/20151218/us-east-1/s3/aws4_request'}, 
       {u'x-amz-date': u'20151218T000000Z'}, 
       {u'bucket': u'leasy'}, 
       [u'starts-with', u'$key', u'']], 
u'expiration': u'2015-12-18T04:59:32Z'} 

Trả lời

2

Tìm thấy một giải pháp: phải cấu hình một cách rõ ràng cho khách hàng s3 để sử dụng chữ ký mới của Amazon v4. Lỗi xảy ra vì nó mặc định là một phiên bản cũ hơn, gây ra sự không khớp. Bit của một facepalm - tại thời điểm này đã không được viết bằng boto3 docs, mặc dù folks tại Amazon nói nó nên được sớm.

Phương pháp này được đơn giản hóa vì nó bây giờ trả về chính xác các trường bắt buộc:

def s3_upload_creds(name): 
    BUCKET = 'mybucket' 
    REGION = 'us-west-1' 
    s3 = boto3.client('s3', region_name=REGION, config=Config(signature_version='s3v4')) 
    key = '${filename}' 
    return s3.generate_presigned_post(
     Bucket = BUCKET, 
     Key = key 
    ) 

Có nghĩa là hình thức có thể dễ dàng tạo ra:

<html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
    </head> 
    <body> 
    {{ creds }} 
     <form action="https://mybucket.s3.amazonaws.com" method="post" enctype="multipart/form-data"> 
     {% for key, value in creds.fields.items() %} 
      <input type="hidden" name="{{ key }}" value="{{ value }}" /> 
     {% endfor %} 
     File: 
     <input type="file" name="file" /> <br /> 
    <input type="submit" name="submit" value="Upload to Amazon S3" /> 
    </form> 
</html> 

Cheers

+0

vĩ đại giải pháp! Đã thử thực hiện nó theo cách của bạn nhưng tôi vẫn nhận được cùng một lỗi từ S3. Tôi nhận thấy rằng các trường được trả về không bao gồm "Loại nội dung". Bạn có thể làm cho nó hoạt động mà không bao gồm loại nội dung không? – Brosef

+0

@Brosef Đừng nhớ trường nào được trả về bởi generate_presigned_post. Tôi tin rằng thư viện được thiết kế để trả lại tất cả các lĩnh vực cần thiết. Bạn đã kiểm tra các tài liệu boto mới nhất chưa? Họ có thể đã thay đổi kể từ khi tôi trả lời. –

Các vấn đề liên quan