本文涉及到的所有内容都是以utf-8编码的。 1. 表单内容

    
File to upload to S3:

上传地址的s3-bucket.s3.amazonaws.com中s3-bucket为使用者所拥有的bucket。上述表单使用了一些常用的字段:

  1. key 上传的文件名;
  2. AWSAccessKeyId 从Amazon获得的access key;
  3. acl 访问控制,可以设置为:private(私有), public-read(公开), public-read-write, authenticated-read.
  4. success_action_redirect 上传成功后浏览器被重定向到这个地址,并且附带上bucke/key/etag三个参数和文件的hash值;
  5. policy 表单鉴权策略,base64编码的格式字符串;下面单独介绍;
  6. signature policy和AWS Secret Key的签名结果,用于保证上传是合法的;
  7. content-type 文件mime类型,默认为 application/octet-stream , 应填写该值便于浏览器识别文件类型;
  8. file 上传的文件。 policy policy用于保证该表单是由合法的S3用户所创建的;policy为JSON格式的字符串:
{"expiration": "2009-01-01T00:00:00Z",
  "conditions": [
    {"bucket": "s3-bucket"},
    ["starts-with", "$key", "uploads/"],
    {"acl": "private"},
    {"success_action_redirect": "http://localhost/"},
    ["starts-with", "$Content-Type", ""],
    ["content-length-range", 0, 1048576]
  ]
}

expiration: 表示policy的有效时间; conditions: policy规则,应包含表单中所有的字段,所以这里列出了acl, success_action_redirect, 和 Content-Type;同时policy包含了content-length-range,用于限制上传的文件大小;

policy有3中类型的规则:

  1. Equality: 表单中的字段值设置为相应的字符串,例如:{“acl”: “private”}
  2. Starts-With:检查表单字段值是否以给定的字符串开始,为一个三元组,例如:[“starts-with”, “$key”, “uploads/”], $key为表单字段名,表单字段的值必须是“upload/”开头的;
  3. Content length:三元组,表示文件长度的最小、最大值。

2. 签名

  1. 首先将policy用base64编码,将其放到表单的policy字段中;
  2. 用AWS secret key作为密码将policy签名,算法为SHA-1 HMAC; 签名后的结果再用base64编码; 示例代码:

Ruby

require 'base64'
require 'openssl'
require 'digest/sha1'

policy = Base64.encode64(policy_document).gsub("\n","")

signature = Base64.encode64(
    OpenSSL::HMAC.digest(
        OpenSSL::Digest::Digest.new('sha1'), 
        aws_secret_key, policy)
    ).gsub("\n","")

Java

import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

String policy = (new BASE64Encoder()).encode(
    policy_document.getBytes("UTF-8")).replaceAll("\n","").replaceAll("\r","");

Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
    aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
    hmac.doFinal(policy.getBytes("UTF-8")))
    .replaceAll("\n", "");

Python

import base64
import hmac, sha

policy = base64.b64encode(policy_document)

signature = base64.b64encode(
    hmac.new(aws_secret_key, policy, sha).digest())

本文为翻译缩略版,原文出处:http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434&categoryID=55 更多详细内容,请参考手册:http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?UsingHTTPPOST.html


Simon Lee

My blog