【发布时间】:2016-03-04 15:05:17
【问题描述】:
我正在尝试与 Amazon Product Affiliate REST API 集成,我拒绝使用 SOAP 集成,请不要在此处提出 Soap,我要使用 REST,我使用的是最新的 API 版本,是 2013 年 8 月 1 日,我按照文档进行操作,不知何故,我总是返回 403 禁止错误,我到处查看,唯一看到的是,人们对亚马逊上过时的样品感到愤怒,所以我没有让我的集成工作感到沮丧,这是我使用的规范。
VS 2015 面向 .NET 4.5.2 的控制台应用程序 亚马逊 API 版本 08/01/2013
这是我的代码库。
我有一个名为 AmazonRestService 的类 它具有 ItemLookup 所需的所有属性,
在构造函数中,我设置了一些属性,这是每个请求的默认属性,然后我有一个名为 SignAmazonRequest 的方法 它将 AmazonRestService 作为参数,我检查所有有值的字段,我填写需要签名的字符串,
public class AmazonRestService
{
public string Url { get; set; }
public string Operation { get; set; }
public string AWSAccessKeyId { get; set; }
public string SecretKey { get; set; }
public string AssociateTag { get; set; }
public string ItemId { get; set; }
public string IdType { get; set; }
public string[] ResponseGroup { get; set; }
public string Timestamp { get; set; }
public string Signature { get; set; }
public string Version { get; set; }
public AmazonRestService()
{
Url = "http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&";
AWSAccessKeyId = "XXXXXXXXXXXXXXXXXXXXX";
AssociateTag = "xxxx-xx";
SecretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
Version = "2013-08-01";
}
public AmazonRestService SignAmazonRequest(AmazonRestService service)
{
var stringToSign = "";
stringToSign = stringToSign + "AssociateTag=" + service.AssociateTag;
if (!string.IsNullOrEmpty(service.Operation))
{
stringToSign = stringToSign + "&Operation=" + service.Operation;
}
if (!string.IsNullOrEmpty(service.ItemId))
{
stringToSign = stringToSign + "&ItemId=" + service.ItemId;
}
if (!string.IsNullOrEmpty(service.IdType))
{
stringToSign = stringToSign + "&IdType=" + service.IdType;
}
if (service.ResponseGroup.Length > 0)
{
stringToSign = stringToSign + "&ResponseGroup=";
var lastResponse = service.ResponseGroup.Last();
foreach (var response in service.ResponseGroup)
{
stringToSign = stringToSign + response;
if (response != lastResponse)
{
stringToSign = stringToSign + ",";
}
}
}
stringToSign = stringToSign + "&Version=" + service.Version;
stringToSign = stringToSign + "&AWSAccessKeyId=" + service.AWSAccessKeyId + "&Timestamp=" + service.Timestamp;
stringToSign = stringToSign.Replace(",", "%2C");
stringToSign = stringToSign.Replace(":", "%3A");
service.Url = service.Url + stringToSign;
stringToSign = stringToSign + "&Service=AWSECommerceService";
service.Signature = HmacSha256.SignAmazonRequest(service.SecretKey, stringToSign);
service.Url = service.Url + "&Signature=" + service.Signature;
return service;
}
}
一旦准备好对字符串进行签名,我就会在另一个名为 HmacSha256.SignAmazonRequest 的类上调用静态方法 我在哪里传递我的 secretKey 和要签名的字符串,
public static class HmacSha256
{
public static string SignAmazonRequest(string secretKey, string request)
{
var stringToSign = PrepareSignatureEncryption(request);
var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
var hmacSha256 = new HMACSHA256(secretKeyBytes);
var hashBytes = hmacSha256.ComputeHash(bytesToSign);
return Convert.ToBase64String(hashBytes).Replace("+", "%2B").Replace("=", "%3D");
}
private static string PrepareSignatureEncryption(string request)
{
var header = "GET" + Environment.NewLine
+ "webservices.amazon.com" + Environment.NewLine
+ "/once/xml" + Environment.NewLine;
var result = header + request;
return result;
}
}
在 SignAmazonRequest 方法中,我首先按照亚马逊的要求准备字符串,
我有一个名为 PrepareSignatureEncryption 的私有辅助方法 它将要签名的字符串作为参数,并返回一个准备好的格式化字符串,如亚马逊在其文档中显示的那样, 然后将字符串转换为字节, 我将密钥转换为字节, 根据密钥字节生成 HMACSHA256, 用它计算要签名的字符串的哈希值, 我返回转换为base64字符串的字节,
现在,这是我在静态 void main 中的代码。
class Program
{
static void Main(string[] args)
{
var restService = new AmazonRestService();
restService.Operation = "ItemLookup";
restService.IdType = "ASIN";
restService.ItemId = "ASINTOLOOKUP";
restService.ResponseGroup = new string[] { "BrowseNodes", "Images", "ItemAttributes", "Offers", "Reviews", "SalesRank" };
var signedRequest = restService.SignAmazonRequest(restService);
Console.WriteLine(signedRequest.Url);
Console.ReadLine();
try
{
var request = WebRequest.Create(signedRequest.Url);
var response = request.GetResponse();
var doc = new XmlDocument();
doc.Load(response.GetResponseStream());
doc.Save("C:/data.xml");
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
}
知道我哪里出错了吗?
【问题讨论】:
-
我尝试了webservices.amazon.com/scratchpad/index.html,一切正常,我试图在我的代码中获取它,具有相同的时间戳,并且一切看起来与暂存器上的完全一样,按字节排序,并且签名仍然不同,有人对此有所了解吗?
标签: c# api rest amazon-web-services