2

我在 AWS 论坛上问过这个问题,但得到了很多意见但没有评论,我想知道这里是否有人可以对此有所了解?

嗨,我已经尝试编写一个简单的 C# 控制台应用程序来调用 topsites 服务两天了,但仍然遇到签名生成问题。

我已经使用库中的 java 示例进行了测试,并且可以使用我的 accesskeyid 和 secret 成功查询。然后,我使用我的 C# 代码来证明我可以生成相同的签名,并且我的代码会这样做,但是当我随后制作一个请求并针对 api 发出它时,每个人都会返回 403 状态 - 签名不匹配 - 请有人帮忙我找出问题所在?我用这个把头发扯掉了。

C#代码:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace ConsoleApplication1
{
    class Program
    {
        private static string baseUrl = ConfigurationManager.AppSettings["baseUrl"];
        private static string accessKeyId = ConfigurationManager.AppSettings["accessKeyId"];
        private static string accessKey = ConfigurationManager.AppSettings["accessKey"];
        private static string serviceVersion = ConfigurationManager.AppSettings["serviceVersion"];
        static void Main(string[] args)
        {
            HttpClient client = new HttpClient();
            string requestParameters = "AWSAccessKeyId=" + accessKeyId + "&Action=TopSites&Count=10&CountryCode=&ResponseGroup=Country&SignatureMethod=HmacSHA256&SignatureVersion=2&Start=1001&Timestamp=" + Amazon.Util.AWSSDKUtils.FormattedCurrentTimestampISO8601;
            var signature = generateSignature(requestParameters);
            var url = "http://" + baseUrl + "?" + requestParameters + "&Signature=" + signature;
            HttpResponseMessage message = client.GetAsync(url).Result;

            Console.ReadKey();
        }
        private static string generateSignature(string queryParameters)
        {
            string stringToSign = "GET\n" + baseUrl + "\n/\n" + queryParameters;
            var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
            var secretKeyBytes = Encoding.UTF8.GetBytes(accessKey);
            var hmacSha256 = new HMACSHA256(secretKeyBytes);
            var hashBytes = hmacSha256.ComputeHash(bytesToSign);
            var signature = System.Net.WebUtility.UrlEncode(Convert.ToBase64String(hmacSha256.Hash));
            Trace.Write("String to sign:{0}", signature);
            return signature;
        }
    }
}

生成的请求(来自 Fiddler): GET http://ats.amazonaws.com/?AWSAccessKeyId=REMOVED&Action=TopSites&Count=10&CountryCode=&ResponseGroup=Country&SignatureMethod=HmacSHA256&SignatureVersion=2&Start=1001&Timestamp=2014-11-20T16:57:52.422Z&Signature=vdKOotQYRmo%NYJJL3ecrGEcGAotQYRmo%XJevzL3ecRGY9 3D HTTP/1.1 主机:ats.amazonaws.com 连接:Keep-Alive

响应:HTTP/1.1 403 禁止服务器:Apache-Coyote/1.1 传输编码:分块日期:2014 年 11 月 20 日星期四 16:57:52 GMT

16d SignatureDoesNotMatch我们计算的请求签名与您提供的签名不匹配。检查您的 AWS 秘密访问密钥和签名方法。有关详细信息,请参阅服务文档。84291dc8-a35e-7dc3-7cc1-56fe20b5b236 0

4

1 回答 1

0

根据 Darrel 的评论以及来自 Java 应用程序和我的示例应用程序的请求之间的广泛比较,我已经能够使用包括上面示例之一在内的多个请求正确查询服务。这似乎是一个问题,即签名的请求字符串在主机名前面有一个错误的空格字符,为了增加弹性,我正在使用适用于 .Net 的 Amazon AWS 开发工具包来根据他们的要求执行 URL 编码,以确保编码是正确的。

这是工作示例代码:

using System;
using System.Configuration;
using System.Diagnostics;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;   

namespace ConsoleApplication1
{
    class Program
    {
        private static string baseUrl = ConfigurationManager.AppSettings["AlexaServiceUrl"];
        private static string accessKeyId = ConfigurationManager.AppSettings["AlexaAccessKeyId"];
        private static string accessKey = ConfigurationManager.AppSettings["AlexaAccessKey"];
        private static string serviceVersion = ConfigurationManager.AppSettings["AlexaServiceVersion"];
        static void Main(string[] args)
        {
            HttpClient client = new HttpClient();
            string requestParameters = "AWSAccessKeyId=" + accessKeyId + "&Action=TopSites&Count=10&CountryCode=&ResponseGroup=Country&SignatureMethod=HmacSHA256&SignatureVersion=2&Start=1001&Timestamp=" + Amazon.Util.AWSSDKUtils.UrlEncode(Amazon.Util.AWSSDKUtils.FormattedCurrentTimestampISO8601, false);
            var signature = generateSignature(requestParameters);
            var url = "http://" + baseUrl + "/?" + requestParameters + "&Signature=" + signature;
            HttpResponseMessage message = client.GetAsync(url).Result;

            Console.ReadKey();
        }
        private static string generateSignature(string queryParameters)
        {
            string stringToSign = String.Format("GET{0}{1}{2}/{3}{4}", "\n", baseUrl, "\n", "\n", queryParameters);
            var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
            var secretKeyBytes = Encoding.UTF8.GetBytes(accessKey);
            var hmacSha256 = new HMACSHA256(secretKeyBytes);
            var hashBytes = hmacSha256.ComputeHash(bytesToSign);
            var signature = Amazon.Util.AWSSDKUtils.UrlEncode(Convert.ToBase64String(hmacSha256.Hash), false);
            Trace.Write("String to sign:{0}", signature);
            return signature;
        }
    }
}

希望这对其他人也有帮助。

于 2014-11-25T18:00:58.363 回答