AWS API Gateway签名 [英] AWS API Gateway Signature

查看:102
本文介绍了AWS API Gateway签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将我的请求签名到亚马逊网关.但是每次我尝试发送POST请求时,它都会告诉我我的签名已过期.任何想法将不胜感激.

I am trying to sign my requests to the amazon gateway. But every time when I try to send a POST request it tells me that my signature has been expired. Any ideas will be appreciated.

推荐答案

您在获取时间或诸如此类的问题上遇到了一些问题.我的有效载荷有问题.因此,如果您要进行GET请求,则您的有效负载为 EMPTY STRING .否则,应将其散列为Json对象.这是我如何在应用程序中执行此操作的示例.该代码可以是原始代码,但我可以100000%正常工作,因为我每天都在使用它.

You have some problem with getting the time or something like that. I had the problem with the payload. So if you are making GET request your payload is an EMPTY STRING. Otherwise it should be hashed Json object. Here is example of how I do it in my application. The code can be raw, but I am 100000% it work, because I am using it every day.

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,我会这样做:

So for example if I want to get all the APIs that are deployed in the Gateway I am doing like this:

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密钥的有趣部分.首先,您需要制作原始有效负载,然后将其传递给我上面给您的方法:

Here is the interesting part of creating a API Key. First you need to make your raw payload and then pass it to the methods I gave you above:

string payload = "{ \"name\" : \"" + name + "\", \"description\" : \"" + description.Trim() + "\", \"enabled\" : \"True\", \"stageKeys\" : [ ] }";

WebRequest webRequest = RequestSignerAWS.RequestPost("/apikeys", "", payload);

并确保获得创建请求的时间,因为这将导致您遇到的问题.

And make sure you are getting the time of the creating the request, because this will cause you the problem you are having.

这篇关于AWS API Gateway签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆