我正在尝试在C#中集成“ 签名带有签名版本4的AWS请求 ”。不幸的是,Amazon并未对C#的实现提供太多细节。我尝试了运气。但是它会抛出此错误消息
“远程服务器返回错误:(403)禁止。
注意:我已经在Postman上工作了。但是无法使其在C#中工作。 接收错误:消息=“远程服务器返回错误:(403)禁止。
我已经使用本文档对https://docs.amazonaws.cn/en_us/general/latest/gr/sigv4_signing.html进行了签名
public WebRequest RequestPost(string canonicalUri, string canonicalQueriString, string jsonString)
{
string hashedRequestPayload = CreateRequestPayload(jsonString);
string authorization = Sign(hashedRequestPayload, "PUT", canonicalUri, canonicalQueriString);
string requestDate = DateTime.ParseExact(DateTime.UtcNow.ToString(), "YYYYMMDD'T'HHMMSS'Z'", CultureInfo.InvariantCulture).ToString();
WebRequest webRequest = WebRequest.Create(canonicalUri + canonicalQueriString);
webRequest.Method = "PUT";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
webRequest.ContentLength = jsonString.Length;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(jsonString);
Stream newStream = webRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
using (WebResponse response = webRequest.GetResponse())
{
StreamReader responseReader = new StreamReader(response.GetResponseStream());
var responseJson = responseReader.ReadToEnd();
}
return webRequest;
}
const string RegionName = "eu-west-1"; //This is the regionName
const string ServiceName = "execute-api";
const string Algorithm = "AWS4-HMAC-SHA256";
const string ContentType = "application/json";
const string Host = "<hostname>";
const string SignedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
private static string CreateRequestPayload(string jsonString)
{
//Here should be JSON object of the model we are sending with POST request
//var jsonToSerialize = new { Data = String.Empty };
//We parse empty string to the serializer if we are makeing GET request
//string requestPayload = new JavaScriptSerializer().Serialize(jsonToSerialize);
string hashedRequestPayload = HexEncode(Hash(ToBytes(jsonString)));
return hashedRequestPayload;
}
private static string Sign(string hashedRequestPayload, string requestMethod, string canonicalUri, string canonicalQueryString)
{
var currentDateTime = DateTime.UtcNow;
var accessKey = "";
var secretKey = "";
var dateStamp = currentDateTime.ToString("yyyyMMdd");
//var requestDate = currentDateTime.ToString("YYYYMMDD'T'HHMMSS'Z");
var requestDate = DateTime.ParseExact(currentDateTime.ToString(), "YYYYMMDD'T'HHMMSS'Z'", CultureInfo.InvariantCulture);
var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, RegionName, ServiceName);
var headers = new SortedDictionary<string, string> {
{ "content-type", ContentType },
{ "host", Host },
{ "x-amz-date", requestDate.ToString() }
};
string canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
// Task 1: Create a Canonical Request For Signature Version 4
string canonicalRequest = requestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + SignedHeaders + "\n" + hashedRequestPayload;
string hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
string stringToSign = Algorithm + "\n" + requestDate + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
// Task 3: Calculate the AWS Signature Version 4
byte[] signingKey = GetSignatureKey(secretKey, dateStamp, RegionName, ServiceName);
string signature = HexEncode(HmacSha256(stringToSign, signingKey));
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
string authorization = string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
Algorithm, accessKey, dateStamp, RegionName, ServiceName, SignedHeaders, signature);
return authorization;
}
private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
{
byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
byte[] kRegion = HmacSha256(regionName, kDate);
byte[] kService = HmacSha256(serviceName, kRegion);
return HmacSha256("aws4_request", kService);
}
private static byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
private static byte[] Hash(byte[] bytes)
{
return SHA256.Create().ComputeHash(bytes);
}
private static byte[] HmacSha256(string data, byte[] key)
{
return new HMACSHA256(key).ComputeHash(ToBytes(data));
}
答案 0 :(得分:-1)
您愿意使用HttpClient
而不是WebRequest
吗?在那种情况下,我创建了一个名为AwsSignatureVersion4的NuGet程序包,该程序包已通过验证可与AWS API Gateway一起使用。