云:AWS
SDK版本:java-aws-SDK-1.10.49
。
我想为我正在上传的对象进化对象锁定。
下面是我的代码,它正在生成aws
signature 4标头,但我仍然无法解决该问题。
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class AWSV4Auth {
private AWSV4Auth() {
}
public static class Builder {
private String accessKeyID;
private String secretAccessKey;
private String regionName;
private String serviceName;
private String httpMethodName;
private String canonicalURI;
private TreeMap<String, String> queryParametes;
private TreeMap<String, String> awsHeaders;
private String payload;
private boolean debug = false;
public Builder(String accessKeyID, String secretAccessKey) {
this.accessKeyID = accessKeyID;
this.secretAccessKey = secretAccessKey;
}
public Builder regionName(String regionName) {
this.regionName = regionName;
return this;
}
public Builder serviceName(String serviceName) {
this.serviceName = serviceName;
return this;
}
public Builder httpMethodName(String httpMethodName) {
this.httpMethodName = httpMethodName;
return this;
}
public Builder canonicalURI(String canonicalURI) {
this.canonicalURI = canonicalURI;
return this;
}
public Builder queryParametes(TreeMap<String, String> queryParametes) {
this.queryParametes = queryParametes;
return this;
}
public Builder awsHeaders(TreeMap<String, String> awsHeaders) {
this.awsHeaders = awsHeaders;
return this;
}
public Builder payload(String payload) {
this.payload = payload;
return this;
}
public Builder debug() {
this.debug = true;
return this;
}
public AWSV4Auth build() {
return new AWSV4Auth(this);
}
}
private String accessKeyID;
private String secretAccessKey;
private String regionName;
private String serviceName;
private String httpMethodName;
private String canonicalURI;
private TreeMap<String, String> queryParametes;
private TreeMap<String, String> awsHeaders;
private String payload;
private boolean debug = false;
/* Other variables */
private final String HMACAlgorithm = "AWS4-HMAC-SHA256";
private final String aws4Request = "aws4_request";
private String strSignedHeader;
private String xAmzDate;
private String currentDate;
private AWSV4Auth(Builder builder) {
accessKeyID = builder.accessKeyID;
secretAccessKey = builder.secretAccessKey;
regionName = builder.regionName;
serviceName = builder.serviceName;
httpMethodName = builder.httpMethodName;
canonicalURI = builder.canonicalURI;
queryParametes = builder.queryParametes;
awsHeaders = builder.awsHeaders;
payload = builder.payload;
debug = builder.debug;
/* Get current timestamp value.(UTC) */
xAmzDate = getTimeStamp();
currentDate = getDate();
}
/**
* Task 1: Create a Canonical Request for Signature Version 4.
*
* @return
*/
private String prepareCanonicalRequest() {
StringBuilder canonicalURL = new StringBuilder("");
/* Step 1.1 Start with the HTTP request method (GET, PUT, POST, etc.), followed by a newline character. */
canonicalURL.append(httpMethodName).append("\n");
/* Step 1.2 Add the canonical URI parameter, followed by a newline character. */
canonicalURI = canonicalURI == null || canonicalURI.trim().isEmpty() ? "/" : canonicalURI;
canonicalURL.append(canonicalURI).append("\n");
/* Step 1.3 Add the canonical query string, followed by a newline character. */
StringBuilder queryString = new StringBuilder("");
if (queryParametes != null && !queryParametes.isEmpty()) {
for (Map.Entry<String, String> entrySet : queryParametes.entrySet()) {
String key = entrySet.getKey();
String value = entrySet.getValue();
queryString.append(key).append("=").append(encodeParameter(value)).append("&");
}
/* @co-author https://github.com/dotkebi @git #1 @date 16th March, 2017 */
queryString.deleteCharAt(queryString.lastIndexOf("&"));
queryString.append("\n");
} else {
queryString.append("\n");
}
canonicalURL.append(queryString);
/* Step 1.4 Add the canonical headers, followed by a newline character. */
StringBuilder signedHeaders = new StringBuilder("");
if (awsHeaders != null && !awsHeaders.isEmpty()) {
for (Map.Entry<String, String> entrySet : awsHeaders.entrySet()) {
String key = entrySet.getKey();
String value = entrySet.getValue();
signedHeaders.append(key).append(";");
canonicalURL.append(key).append(":").append(value).append("\n");
}
/* Note: Each individual header is followed by a newline character, meaning the complete list ends with a newline character. */
canonicalURL.append("\n");
} else {
canonicalURL.append("\n");
}
/* Step 1.5 Add the signed headers, followed by a newline character. */
strSignedHeader = signedHeaders.substring(0, signedHeaders.length() - 1); // Remove last ";"
canonicalURL.append(strSignedHeader).append("\n");
/* Step 1.6 Use a hash (digest) function like SHA256 to create a hashed value from the payload in the body of the HTTP or HTTPS. */
payload = payload == null ? "" : payload;
canonicalURL.append(generateHex(payload));
if (debug) {
System.out.println("##Canonical Request:\n" + canonicalURL.toString());
}
return canonicalURL.toString();
}
/**
* Task 2: Create a String to Sign for Signature Version 4.
*
* @param canonicalURL
* @return
*/
private String prepareStringToSign(String canonicalURL) {
String stringToSign = "";
/* Step 2.1 Start with the algorithm designation, followed by a newline character. */
stringToSign = HMACAlgorithm + "\n";
/* Step 2.2 Append the request date value, followed by a newline character. */
stringToSign += xAmzDate + "\n";
/* Step 2.3 Append the credential scope value, followed by a newline character. */
stringToSign += currentDate + "/" + regionName + "/" + serviceName + "/" + aws4Request + "\n";
/* Step 2.4 Append the hash of the canonical request that you created in Task 1: Create a Canonical Request for Signature Version 4. */
stringToSign += generateHex(canonicalURL);
if (debug) {
System.out.println("##String to sign:\n" + stringToSign);
}
return stringToSign;
}
/**
* Task 3: Calculate the AWS Signature Version 4.
*
* @param stringToSign
* @return
*/
private String calculateSignature(String stringToSign) {
try {
/* Step 3.1 Derive your signing key */
byte[] signatureKey = getSignatureKey(secretAccessKey, currentDate, regionName, serviceName);
/* Step 3.2 Calculate the signature. */
byte[] signature = HmacSHA256(signatureKey, stringToSign);
/* Step 3.2.1 Encode signature (byte[]) to Hex */
String strHexSignature = bytesToHex(signature);
return strHexSignature;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* Task 4: Add the Signing Information to the Request. We'll return Map of
* all headers put this headers in your request.
*
* @return
*/
public Map<String, String> getHeaders() {
awsHeaders.put("x-amz-date", xAmzDate);
/* Execute Task 1: Create a Canonical Request for Signature Version 4. */
String canonicalURL = prepareCanonicalRequest();
/* Execute Task 2: Create a String to Sign for Signature Version 4. */
String stringToSign = prepareStringToSign(canonicalURL);
/* Execute Task 3: Calculate the AWS Signature Version 4. */
String signature = calculateSignature(stringToSign);
if (signature != null) {
Map<String, String> header = new HashMap<String, String>(0);
header.put("x-amz-date", xAmzDate);
header.put("Authorization", buildAuthorizationString(signature));
if (debug) {
System.out.println("##Signature:\n" + signature);
System.out.println("##Header:");
for (Map.Entry<String, String> entrySet : header.entrySet()) {
System.out.println(entrySet.getKey() + " = " + entrySet.getValue());
}
System.out.println("================================");
}
return header;
} else {
if (debug) {
System.out.println("##Signature:\n" + signature);
}
return null;
}
}
/**
* Build string for Authorization header.
*
* @param strSignature
* @return
*/
private String buildAuthorizationString(String strSignature) {
return HMACAlgorithm + " "
+ "Credential=" + accessKeyID + "/" + getDate() + "/" + regionName + "/" + serviceName + "/" + aws4Request + ","
+ "SignedHeaders=" + strSignedHeader + ","
+ "Signature=" + strSignature;
}
/**
* Generate Hex code of String.
*
* @param data
* @return
*/
private String generateHex(String data) {
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(data.getBytes("UTF-8"));
byte[] digest = messageDigest.digest();
return String.format("%064x", new java.math.BigInteger(1, digest));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* Apply HmacSHA256 on data using given key.
*
* @param data
* @param key
* @return
* @throws Exception
* @reference:
* http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
*/
private byte[] HmacSHA256(byte[] key, String data) throws Exception {
String algorithm = "HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF8"));
}
/**
* Generate AWS signature key.
*
* @param key
* @param date
* @param regionName
* @param serviceName
* @return
* @throws Exception
* @reference
* http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
*/
private byte[] getSignatureKey(String key, String date, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF8");
byte[] kDate = HmacSHA256(kSecret, date);
byte[] kRegion = HmacSHA256(kDate, regionName);
byte[] kService = HmacSHA256(kRegion, serviceName);
byte[] kSigning = HmacSHA256(kService, aws4Request);
return kSigning;
}
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
/**
* Convert byte array to Hex
*
* @param bytes
* @return
*/
private String bytesToHex(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] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars).toLowerCase();
}
/**
* Get timestamp. yyyyMMdd'T'HHmmss'Z'
*
* @return
*/
private String getTimeStamp() {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));//server timezone
return dateFormat.format(new Date());
}
/**
* Get date. yyyyMMdd
*
* @return
*/
private String getDate() {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));//server timezone
return dateFormat.format(new Date());
}
private String encodeParameter(String param){
try {
return URLEncoder.encode(param, "UTF-8");
} catch (Exception e) {
return URLEncoder.encode(param);
}
}
}
现在包含我的授权头的请求如下
AWS4-HMAC-SHA256凭据=xxxx/xx/us-East-1/s3/aws4_request, SignedHeaders=内容类型;x-amz-date; x-amz-对象-锁-法律-持有;x-amz-对象-锁-模式;x-amz-对象-锁-保留-直到-日期,签名=xxx
但是下面的例外还是来了,请帮助
com.amazonaws.services.s3.model.AmazonS3Exception: Put Object requests with Object Lock parameters require AWS Signature Version 4 (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: 30E27045CC75BD10), S3 Extended Request ID: sTQY2dy9o21y8iO0eeD/33V9DNjoLEwpElgyQi3S3FlC5P38DWRudzV1tErpON14pCAqUtJVHjM=
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1307)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:894)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:597)
at com.amazonaws.http.AmazonHttpClient.doExecute(AmazonHttpClient.java:363)
at com.amazonaws.http.AmazonHttpClient.executeWithTimer(AmazonHttpClient.java:329)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:308)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Cli
ent.java:3659)
我建议您不要自己编码签名生成,而是利用AWS SDK为Java提供的实现。
这个答案向您展示了如何从Java在AWS中生成签名
问题内容: 因此,像往常一样,我尝试在SO上找到这个问题,但还是没有运气。 我知道答案是“是的,您可以修改req对象”,但是关于req对象参数什么也没说。 例如,以下代码将引发错误: 错误: 我想这与没有“ SET”方法的属性有关,或者与之类似。 在某些情况下可以派上用场。 一种将快速链接转换为完整请求并代理这些请求的服务。 只需修改参数,然后再将其发送给您不想修改的其他功能。 问题 是,有没有办
当前的请求对象由think\Request类负责,在很多场合下并不需要实例化调用,通常使用依赖注入即可。在其它场合(例如模板输出等)则可以使用think\facade\Request静态类操作。 [TOC=2,3] 请求对象调用 在控制器中通常情况下有两种方式进行依赖注入。 构造方法注入 <?php namespace app\index\controller; use think\Reque
问题内容: 问题在于确定以下符号之间的权衡: 基于JSON : 基于数组 : 关于同一问题的这篇文章,我已经决定(在前端)使用JSON对象表示法而不是对象数组,因为它符合我的要求,更好的性能和更少的浏览器代码。 但是问题在于列表本身不是静态的。我的意思是,该列表正在生成,即从DB(NoSQL)获取/存储,并通过服务器上的JavaAPI为新条目创建。我无法决定在后端应使用哪种表示法(最终也会影响UI
问题内容: 方法签名是方法声明的一部分。它是方法名称和参数列表的组合。 因此,我只想传递构成所有参数的请求对象,而不是指定参数列表。并非所有方法都正确,但是想在任何可能的地方尝试。 举例来说 也可以写成 但是由于他不知道参数,因此呼叫者可能会感到困惑。 这是一个好习惯吗??? 问题答案: 我不会在“可能的地方”这样做- 但这通常是一个好主意,是的。基本上,请问问自己,参数本身是否构成一个连贯的单个
来自客户端网页的数据作为全局请求对象发送到服务器。要处理请求数据,请求对旬应该从Flask模块导入。 请求对象的重要属性如下所列 - - 它是包含表单参数及其值的键和值对的字典对象。 - 解析问号()后的URL部分查询字符串的内容。 - 保存Cookie名称和值的字典对象。 - 与上传文件有关的数据。 - 当前请求方法。
概述 Django 使用Request 对象和Response 对象在系统间传递状态。 当请求一个页面时,Django会建立一个包含请求元数据的 HttpRequest 对象。 当Django 加载对应的视图时,HttpRequest 对象将作为视图函数的第一个参数。每个视图会返回一个HttpResponse 对象。 本文档对HttpRequest 和HttpResponse 对象的API 进行说