java - 无法签署 aws s3 发布请求
问题描述
我想创建一个带有发布策略的签名请求,用于在 s3 上上传对象。此处描述的签名计算https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html#sigv4-post-signature-calc
这是我的政策
{
"expiration": "2020-08-02T21:24:00.000Z",
"conditions": [
{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
{"x-amz-credential": "my_aws_access_key_id/20200702/us_east_1/s3/aws4_request"},
{"x-amz-date": "20200702T000000Z"},{"bucket": "my_bucket_name"},
["starts-with", "$key", "prefix/"]
]
}
这是我的代码,其中计算请求的帖子参数:
public void createParams() throws Exception {
String secretKey = getAwsSecretKey();
String region = getRegionName();
String policy = "{" +
"\"expiration\": \"2020-08-02T21:24:00.000Z\"," +
"\"conditions\": [" +
"{\"x-amz-algorithm\": \"AWS4-HMAC-SHA256\"}," +
"{\"x-amz-credential\": \"my_aws_access_key_id/20200702/us_east_1/s3/aws4_request\"}," +
"{\"x-amz-date\": \"20200702T000000Z\"},{\"bucket\": \"my_bucket_name\"}," +
"[\"starts-with\", \"$key\", \"prefix/\"]" +
"]" +
"}";
byte[] b64PolicyBytes = toBase64(policy.getBytes(StandardCharsets.UTF_8));
String b64policy = new String(b64PolicyBytes);
Map<String, String> params = new HashMap<>();
params.put("policy", b64policy);
params.put("x-amz-algorithm", "AWS4-HMAC-SHA256");
params.put("x-amz-credential", "aws_access_key_id/20200702/us_east_1/s3/aws4_request");
params.put("x-amz-date", "20200702T000000Z");
byte[] key = createSignedKey(secretKey, "20200702", region);
byte[] sign = hmac(b64policy.getBytes(StandardCharsets.UTF_8), key);
params.put("x-amz-signature", toHex(sign));
params.forEach((k, value) -> System.out.printf("%s: %s%n", k, value));
}
private byte[] createSignedKey(String secretKey, String date, String region) throws Exception {
byte[] s1 = hmac("AWS4".concat(secretKey).getBytes(StandardCharsets.UTF_8), date.getBytes());
byte[] s2 = hmac(s1, region.getBytes(StandardCharsets.UTF_8));
byte[] s3 = hmac(s2, "s3".getBytes(StandardCharsets.UTF_8));
return hmac(s3, "aws4_request".getBytes(StandardCharsets.UTF_8));
}
byte[] toBase64(byte[] policy) {
return Base64.getEncoder().encode(policy);
}
byte[] hmac(byte[] data, byte[] key) throws Exception {
String algorithm = "HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data);
}
static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
static String toHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
如果您调用 createParams() 方法后参数将被打印。
接下来我去邮递员并像这样构造表单数据请求:
POST https://my_bucket_name.s3.amazonaws.com
policy:policy...
x-amz-credential:aws_access_key_id/20200702/us-east-1/s3/aws4_request
x-amz-algorithm:AWS4-HMAC-SHA256
x-amz-date:20200701T000000Z
x-amz-signature:D90FEF721FD70812502A6D61CEC9CAD700EBEC810A2BB7C6439E3A088B27FFC7
key:ttt/object_name
和 aws 以错误响应:
<?xml version="1.0" encoding="UTF-8"?>
<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>aws_access_key_id</AWSAccessKeyId>
<StringToSign>my policy base64 string</StringToSign>
<SignatureProvided>...</SignatureProvided>
<StringToSignBytes>...</StringToSignBytes>
<RequestId>F292097E276C15C3</RequestId>
<HostId>...</HostId>
</Error>
我做错了什么?
解决方案
推荐阅读
- flutter - 如何使用 vscode 在 windows pc 上为 ios 构建 .ipa 文件?
- sql - 使用 SQL 将字符串转换为时间
- python - python多进程使用map,但有一个子进程正在运行
- lisp - 如何在 LISP 中反转列表及其子列表的元素?
- python - Pyspark:pyspark.sql.utils 列不明确
- javascript - 使用带有jQuery验证器插件的Ajax制作计算器,但Ajax在验证前进行提交
- html - CSS:将div向上移动其高度的一半?
- mips - MIPS - 不能使用奇数寄存器进行双精度乘法运算?
- c++ - 我收到此错误“错误:预期的';' 在声明结束时”尝试在 VSC 中编译。我该如何解决这个问题?
- elasticsearch - Kibana 从部署在 AWS 不同数据中心的多个弹性搜索实例中获取弹性搜索数据