我一直在尝试使用 Amazon SES Https Query API 发送电子邮件。但我计算并发送到 AWS 的签名不被接受。
我收到此错误消息。
<ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<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.</Message>
</Error>
<RequestId>c97bd130-24c9-11e6-924a-b59d7ac9182b</RequestId>
</ErrorResponse>
这是我的Java代码
public class SendSESMail {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, IOException, SignatureException {
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
String dateString = format.format(new Date());
final String ENDPOINT = "https://email.us-east-1.amazonaws.com";
final String AWS_ACCESS = "ACCESS_KEY";
final String AWS_SECRET = "SECRET_KEY";
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost post = new HttpPost(ENDPOINT);
String authString = generateAuthHeader(AWS_ACCESS, AWS_SECRET, dateString);
List<NameValuePair> formVals = new ArrayList<>();
formVals.add(new BasicNameValuePair("Action", "SendRawEmail"));
formVals.add(new BasicNameValuePair("Destination.ToAddresses.member.1", "bhanuka.yd@gmail.com"));
formVals.add(new BasicNameValuePair("Message.Body.Text.Data", "I hope you see the body."));
formVals.add(new BasicNameValuePair("Message.Subject.Data", "This is a Unique Subject"));
formVals.add(new BasicNameValuePair("Source", "test@test.com"));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formVals);
post.setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.toString());
post.setHeader("Date", dateString);
post.setHeader("X-Amzn-Authorization", authString);
post.setEntity(formEntity);
HttpResponse response = httpClient.execute(post);
response.getEntity().writeTo(System.out);
}
public static String generateAuthHeader(String accessKey, String secret, String dateString) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
String authHeaderVal = "AWS3-HTTPS AWSAccessKeyId=" + accessKey + ",Algorithm=HmacSHA256,Signature=";
authHeaderVal += generateSignature(dateString, secret);
return authHeaderVal;
}
public static String generateSignature(String message, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKey);
return Base64.encodeBase64URLSafeString(sha256_HMAC.doFinal(message.getBytes()));
}
}
我第一次尝试,它给了我这个错误
<ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
<Error>
<Type>Sender</Type>
<Code>ValidationError</Code>
<Message>1 validation error detected: Value null at 'rawMessage' failed to satisfy constraint: Member must not be null</Message>
</Error>
<RequestId>9a986157-24ca-11e6-9864-3fdeb433e3c8</RequestId>
</ErrorResponse>
是因为签名末尾有一个"="符号,所以我用了
encodeBase64URLSafeString();
将签名转换为 Base64 而不是
encodeBase64String();
所以我在这里做错了什么,请有人在这里帮我谢谢。
我终于发现我可以使用签名 V4 来验证我的 HTTP 请求。
任何有此问题的人都可以按照以下链接中的确切过程进行操作,您将能够进行身份验证。
要记住的一件事是,请求时间应采用 UTC 格式ISO8601
这是一种以 UTC 时区计算当前时间的方法。
public static String getUTCTimeISO8601Format() {
TimeZone timeZone = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(timeZone);
SimpleDateFormat iso8601Format = new SimpleDateFormat("YYYYMMdd'T'HHmmss'Z'");//ISO8601 B8601DZw.d format
iso8601Format.setTimeZone(timeZone);
return iso8601Format.format(calendar.getTime());
}