当我从REST客户端调用API端点时,我通过签名来解决错误。
请求:
主持人:https://xxx.execute-api.ap-southeast-1.amazonaws.com/latest/api/name
授权:AWS4-HMAC-SHA256凭据=
{AWSKEY}
/ 20160314 / ap-southeast-1 / execute-api / aws4_request,SignedHeaders = host; range; x-amz-date ,签名={signature}
X-Amz-Date :20160314T102915Z
响应:
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. The Canonical String for this request should have been 'xxx' "
}
从Java代码开始,我遵循AWS参考如何生成签名。
String secretKey = "{mysecretkey}";
String dateStamp = "20160314";
String regionName = "ap-southeast-1";
String serviceName = "execute-api";
byte[] signature = getSignatureKey(secretKey, dateStamp, regionName, serviceName);
System.out.println("Signature : " + Hex.encodeHexString(signature));
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"));
}
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;
}
我可以在生成签名时知道我的错误吗?
参考如何生成签名:http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
答案 0 :(得分:11)
您可以使用aws-java-sdk-core中的类:https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-core
更具体地说,请求,Aws4Signer和其他一些:
//Instantiate the request
Request<Void> request = new DefaultRequest<Void>("es"); //Request to ElasticSearch
request.setHttpMethod(HttpMethodName.GET);
request.setEndpoint(URI.create("http://..."));
//Sign it...
AWS4Signer signer = new AWS4Signer();
signer.setRegionName("...");
signer.setServiceName(request.getServiceName());
signer.sign(request, new AwsCredentialsFromSystem());
//Execute it and get the response...
Response<String> rsp = new AmazonHttpClient(new ClientConfiguration())
.requestExecutionBuilder()
.executionContext(new ExecutionContext(true))
.request(request)
.errorResponseHandler(new SimpleAwsErrorHandler())
.execute(new SimpleResponseHandler<String>());
如果你想要一个更干净的设计,你可以使用Decorator模式来组成一些优雅的类并隐藏上面的混乱。这里有一个例子:http://www.amihaiemil.com/2017/02/18/decorators-with-tunnels.html
答案 1 :(得分:2)
从上面的代码示例看,您似乎没有创建规范请求,并将其包含在按http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
签名的字符串中不是自己实现这个,而是让你看看使用第三方库。
aws-v4-signer-java是一个轻量级的零依赖库,可以轻松生成AWS V4签名。
String contentSha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
HttpRequest request = new HttpRequest("GET", new URI("https://examplebucket.s3.amazonaws.com?max-keys=2&prefix=J"));
String signature = Signer.builder()
.awsCredentials(new AwsCredentials(ACCESS_KEY, SECRET_KEY))
.header("Host", "examplebucket.s3.amazonaws.com")
.header("x-amz-date", "20130524T000000Z")
.header("x-amz-content-sha256", contentSha256)
.buildS3(request, contentSha256)
.getSignature();
免责声明:我是图书馆作者。
答案 2 :(得分:0)
使用100%Java库而无需附加依赖项,这是可能的,只需使用此处生成的query parameters:
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Formatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
...
private static final String ACCESS_KEY = "...";
private static final String SECRET_KEY = "...";
private static final int expiresTime = 1 * 24 * 60 * 60;
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
public void sign(String protocol, String bucketName, String contentPath) throws Exception {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR_OF_DAY, 24);
String host = bucketName + ".s3-us-west-2.amazonaws.com";
long expireTime = cal.getTimeInMillis() / 1000;
String signString = "GET\n" +
"\n" +
"\n" +
expireTime + "\n" +
"/" + bucketName + contentPath;
SecretKeySpec signingKey = new SecretKeySpec(SECRET_KEY.getBytes(), HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
String signature = URLEncoder.encode(new String(Base64.getEncoder().encode(mac.doFinal(signString.getBytes()))));
System.out.println(signature);
String fullPayload = "?AWSAccessKeyId=" + ACCESS_KEY +
"&Expires=" + expireTime +
"&Signature=" + signature;
System.out.println(protocol + "://" + host + contentPath + fullPayload);
}
...
答案 3 :(得分:0)
签名过程漫长且容易出错,这里有一些提示
答案 4 :(得分:0)
最简单的方法是使用Amazon SDK中的方法和http-client。我遵循以下3个步骤。
步骤1:创建基本的AWS凭证:
BasicAWSCredentials awsCreds = new BasicAWSCredentials(ACCESS_KEY,AWS_DATASHOP_SECRET_KEY);
第2步:创建signableRequest:
DefaultRequest<?> signableRequest = new DefaultRequest<>("aws-service-name");
signableRequest.setHttpMethod(HttpMethodName.GET);
signableRequest.setResourcePath("fooo");
signableRequest.setEndpoint(URI.create(baar));
signableRequest.addParameter("execution_id", executionId);
signableRequest.addHeader("Content-Type", "application/json");
signer.sign(signableRequest, awsCreds);
步骤3:使用AmazonHttpClient执行请求:
new AmazonHttpClient(new ClientConfiguration())
.requestExecutionBuilder()
.executionContext(new ExecutionContext(true))
.request(signableRequest)
.errorResponseHandler((new SimpleAwsErrorHandler()))
.execute(new MyResponseHandler());
确保为HttpResponseHandler
和SimpleAwsErrorHandler
实现MyResponseHandler
如果要使用普通的http客户端,则必须创建一个规范请求并计算最不匹配的签名 。
答案 5 :(得分:0)
您可以调查 AWS 网站共享的代码示例。我使用了一些 util 类和一些我需要的 java 类。所以你不必使用所有的类和其他东西。我留下了下面的链接。