我正在尝试签署我对亚马逊网关的请求。但是每次我尝试发送 POST 请求时,它都会告诉我我的签名已过期。任何想法将不胜感激。
问问题
6849 次
1 回答
9
你在获得时间或类似的事情上遇到了一些问题。我遇到了有效载荷的问题。因此,如果您发出 GET 请求,您的有效负载是EMPTY STRING。否则它应该是散列的 Json 对象。这是我如何在我的应用程序中执行此操作的示例。代码可以是原始的,但我 100000% 可以工作,因为我每天都在使用它。
const string RegionName = "eu-west-1"; //This is the regionName
const string ServiceName = "apigateway";
const string Algorithm = "AWS4-HMAC-SHA256";
const string ContentType = "application/json";
const string Host = "apigateway.eu-west-1.amazonaws.com";
const string SignedHeaders = "content-type;host;x-amz-date";
public static WebRequest RequestGet(string canonicalUri, string canonicalQueriString, string jsonString) {
string hashedRequestPayload = CreateRequestPayload("");
string authorization = Sign(hashedRequestPayload, "GET", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString("yyyyMMddTHHmmss") + "Z";
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Method = "GET";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
return webRequest;
}
public static WebRequest RequestPost(string canonicalUri, string canonicalQueriString, string jsonString)
{
string hashedRequestPayload = CreateRequestPayload(jsonString);
string authorization = Sign(hashedRequestPayload, "POST", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString("yyyyMMddTHHmmss") + "Z";
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Timeout = 20000;
webRequest.Method = "POST";
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);
return webRequest;
}
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 = //Here place your app ACCESS_KEY
var secretKey = //Here is a place for you app SECRET_KEY
var dateStamp = currentDateTime.ToString("yyyyMMdd");
var requestDate = currentDateTime.ToString("yyyyMMddTHHmmss") + "Z";
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 }
};
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));
}
因此,例如,如果我想获取部署在网关中的所有 API,我会这样做:
using(WebResponse response = webRequest.GetResponse()) {
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string responseJson = responseReader.ReadToEnd();
} catch (WebException) {
//Doing something when exception has been thrown
}
这是创建 API 密钥的有趣部分。首先,您需要制作原始有效负载,然后将其传递给我上面给您的方法:
string payload = "{ \"name\" : \"" + name + "\", \"description\" : \"" + description.Trim() + "\", \"enabled\" : \"True\", \"stageKeys\" : [ ] }";
WebRequest webRequest = RequestSignerAWS.RequestPost("/apikeys", "", payload);
并确保您获得了创建请求的时间,因为这会导致您遇到问题。
于 2015-10-02T12:13:32.240 回答