生成AWS Signature v4签名以上传到s3(从v2迁移) [英] Generating an AWS Signature v4 signature for uploading to s3 (migration from v2)
问题描述
我目前有一个可行的实现,其工作方式如下:
UI选择文件=>单击上载=>调用我的后端API以请求签名,因为我不想公开访问权限+秘钥=>返回签名+策略=>将文件上传到s3./p>
这对于v2来说很好用,很花哨.
String base64Policy = (new BASE64Encoder()).encode(policy.toString().getBytes("UTF-8")).replaceAll("\n", "").replaceAll("\r", "");
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(hmac.doFinal(base64Policy.getBytes("UTF-8"))).replaceAll("\n", "");
现在,我很有趣,我的新存储桶位于不支持v2的区域.
我一直在关注AWS文档,但我认为我对有效负载有些误解.我真的需要在整个文件的sha256哈希中传递我的UI吗?因为这似乎有点麻烦,尤其是因为我的文件可以大于1兆.
我尝试使用的代码:
byte[] signatureKey = getSignatureKey(secretKey, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")), bucketRegion, "s3");
StringBuilder sb = new StringBuilder();
for (byte b : signatureKey) {
sb.append(String.format("%02X", b));
}
private static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
private static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm="HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF8"));
}
但是当我尝试使用其余代码时,这会给出无效的签名响应.
我难以忍受,只是误会了: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html 吗?
任何帮助都将不胜感激,因为我一直对这种方式持怀疑态度,并且我宁愿不要大修.
您可以使用标准SDK方法将文件上传到S3,而无需生成签名,请参阅 和 此外,在使用多部分数据时,您还应该考虑使用HTTP标头,例如,请参见以下构建 I currently have a working implementation that works as follows: UI select a file => click upload => call to my backend API to request a signature since I don't want to expose my access + secretkey => return the signature + policy => do an upload to s3. This works fine and dandy for v2. Now I get to the fun bit where my new buckets are in a region where v2 isn't supported. I was following the AWS documentation but I think I am misunderstanding the payload bit a bit. Do I really need to have my UI pass in a sha256 hash of my whole file? Since that would seem to be a bit of a pain, especially since my files can be > 1 gig. The code I was attempting to use: But this gives an invalid signature response when I try to use the rest of my code. Am I derping that hard, and just misunderstanding: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html ? Any help would be much appreciated since I've been hanging my head against this way too long and I'd prefer not to overhaul too much. You can upload a file to S3 by using standard SDK methods without generating a signature, please see the documentation.
But if you need a signature for some reason, I think, the simplest way to generate a signature is to use methods from AWS SDK, please see the following class which extends where and Also you should consider http headers when you use multipart data, for example, please see the following method which builds HttpEntity
这篇关于生成AWS Signature v4签名以上传到s3(从v2迁移)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!AWS4Signer
的来源<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.213</version>
</dependency>
AWSCredentials
可以构建为AWSCredentials awsCredentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey);
String base64Policy = (new BASE64Encoder()).encode(policy.toString().getBytes("UTF-8")).replaceAll("\n", "").replaceAll("\r", "");
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(hmac.doFinal(base64Policy.getBytes("UTF-8"))).replaceAll("\n", "");
byte[] signatureKey = getSignatureKey(secretKey, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")), bucketRegion, "s3");
StringBuilder sb = new StringBuilder();
for (byte b : signatureKey) {
sb.append(String.format("%02X", b));
}
private static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
private static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm="HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF8"));
}
AWS4Signer
:public class AwsAuthUtil extends AWS4Signer {
private String serviceName;
private AWSCredentials credentials;
private String region;
public AwsAuthUtil(AWSCredentials credentials, String region, String serviceName) {
this.credentials = credentials;
this.region = region;
this.serviceName = serviceName;
}
public String getSignature(String policy, LocalDateTime dateTime) {
try {
String dateStamp = dateTime.format(ofPattern("yyyyMMdd"));
return Hex.encodeHexString(hmacSha256(newSigningKey(credentials, dateStamp, region, serviceName), policy));
} catch (Exception e) {
throw new RuntimeException("Error", e);
}
}
private byte[] hmacSha256(byte[] key, String data) throws Exception {
Mac mac = Mac.getInstance(SigningAlgorithm.HmacSHA256.name());
mac.init(new SecretKeySpec(key, SigningAlgorithm.HmacSHA256.name()));
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
}
}
AWS4Signer
is from<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.213</version>
</dependency>
AWSCredentials
can be built asAWSCredentials awsCredentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey);
public HttpEntity buildPostMultipartDataEntity(String objectKey, byte[] data, String signature, LocalDateTime dateTime) {
String dateTimeStr = dateTime.format(ofPattern("yyyyMMdd'T'HHmmss'Z'"));
String date = dateTime.format(ofPattern("yyyyMMdd"));
return MultipartEntityBuilder
.create()
.addTextBody("key", objectKey)
.addTextBody("Policy", policy)
.addTextBody("X-Amz-Signature", signature)
.addTextBody("X-Amz-Algorithm", algorithm)
.addTextBody("X-Amz-Date", dateTimeStr)
.addTextBody("X-Amz-Credential", String.format("%s/%s/%s/s3/aws4_request", accessKey, date, region))
.addBinaryBody("file", data)
.build();
}