我希望通过从VB.NET程序发送包含书籍ISBN号的(概念上)简单请求,从Amazon Web Services(AWS)产品广告API检索书籍详细信息(以XML格式)。我有一个带有AWS Access Key和Secret密钥的Amazon AWS账户。
我可以进入访问AWS的阶段,但得到以下响应:
<?xml version="1.0"?>
<ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2005-10-05/">
<Error><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>556dafef-b59f-4829-8ffe-80668cea9707</RequestId>
</ItemLookupErrorResponse>
我使用的代码如下(这里真正的Access密钥和密钥已被虚拟字符串替换):
Public Shared Function MakeRequestString(IsbnString As String) As String
Dim stringToSign, strTimestamp, strSignature, strSignedRequest, strParamValuePairs As String
stringToSign = "GET" & vbLf 'vbLf is Line feed character Ascii 10
stringToSign &= "webservices.amazon.com" & vbLf
stringToSign &= "/onca/xml" & vbLf
'-----------------------------------------------------------------------
strParamValuePairs = "AWSAccessKeyId=" & GetAWSAccessKey()
strParamValuePairs &= "&IdType=ISBN"
strParamValuePairs &= "&ItemId=" & IsbnString
strParamValuePairs &= "&Operation=ItemLookup"
strParamValuePairs &= "&Service=AWSECommerceService"
strTimestamp = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff")
strParamValuePairs &= "&Timestamp=" & UrlEncode(strTimestamp)
stringToSign = stringToSign & strParamValuePairs
'---------------------------------------------------------------
strSignature = MakeSignature(stringToSign)
'----------------------------------------------------
strSignedRequest = "http://webservices.amazon.com/onca/xml?"
strSignedRequest &= "AWSAccessKeyId=" & GetAWSAccessKey()
strSignedRequest &= "&IdType=ISBN"
strSignedRequest &= "&ItemId=" & IsbnString
strSignedRequest &= "&Operation=ItemLookup"
strSignedRequest &= "&Service=AWSECommerceService"
strSignedRequest &= "&Signature=" & UrlEncode(strSignature)
strSignedRequest &= "&Timestamp=" & UrlEncode(strTimestamp)
Return strSignedRequest
End Function
Private Shared Function MakeSignature(ByVal StringToHash As String) As String
Dim myEncoder As New System.Text.UTF8Encoding
Dim strSecretAccessKey As String = GetSecretKey()
Dim Key As Byte() = myEncoder.GetBytes(strSecretAccessKey)
Dim bytStringToHashAsBytes As Byte() = myEncoder.GetBytes(StringToHash)
Dim myHMACSHA256 As New System.Security.Cryptography.HMACSHA256(Key)
Dim HashCode As Byte() = myHMACSHA256.ComputeHash(bytStringToHashAsBytes)
Return Convert.ToBase64String(HashCode)
End Function
Private Shared Function GetSecretKey() As String
Return "AAAAAAA Secret Key AAAAAAA"
End Function
Private Shared Function GetAWSAccessKey() As String
Return "AAAA Access Key AAAAA"
End Function
要汇编上述代码,我已遵循亚马逊AWS产品广告API开发人员指南示例休息请求(http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html)
注意,在生成签名后的这些指南(步骤9)中,指令是对签名中的加号(+)和等号(=)进行URL编码,然后在签名请求中包含这样的URL编码签名 - 但是在他们在指南中使用的示例中,他们似乎对URL中的其他字符进行URL编码,例如正斜杠字符。我已尝试过URL编码,但无济于事。
关于URL编码,某些参数不包含任何可能存在问题的字符,这包括AWS Access Key。时间戳包含 - 和:字符,Secret键似乎总是有一个正斜杠(/)字符。计算出的签名中将包含特殊字符。
我注意到如果在时间戳中包含空格,那么请求不会进入返回AWS错误的阶段,而是会发现无法找到网页的错误(因此在日期和时间之间的T时间戳。)