C# AWS TranslateText REST API调用添加签名v4

C# AWS TranslateText REST API调用添加签名v4,c#,rest,amazon-web-services,signature,translate,C#,Rest,Amazon Web Services,Signature,Translate,实际上,这不是一个问题,而是那些试图在没有SDK的情况下使用AWS TranslateText的人的答案。我有很多问题,直到我得到一个运行版本 在我看来,此服务的AWS文档并不完整,并且没有太多的示例可供检查(至少对于.Net而言) 起初,我认为我没有生成正确的V4签名,但在再次检查步骤和值之后,我决定使用Postman调用该服务。这很有帮助 邮递员可以生成AWS签名!(是的,我不知道)所以最后我注意到签名值不是问题所在 通过检查请求,我可以看到所需的标题及其一些值 我的问题是我没有发送“x-a

实际上,这不是一个问题,而是那些试图在没有SDK的情况下使用AWS TranslateText的人的答案。我有很多问题,直到我得到一个运行版本

在我看来,此服务的AWS文档并不完整,并且没有太多的示例可供检查(至少对于.Net而言)

起初,我认为我没有生成正确的V4签名,但在再次检查步骤和值之后,我决定使用Postman调用该服务。这很有帮助

邮递员可以生成AWS签名!(是的,我不知道)所以最后我注意到签名值不是问题所在

通过检查请求,我可以看到所需的标题及其一些值

我的问题是我没有发送“x-amz-target”头。 碰巧我发现这个头的值必须是“AWSShineFrontendService_20170701.TranslateText” (我在这里看到了类似的值)

另一个链接也很有帮助

现在我有了一个运行版本,我想分享我的.Net代码。我希望它有帮助:)

使用Newtonsoft.Json.Linq;
使用制度;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
Net系统;
使用System.Security.Cryptography;
使用系统文本;
使用System.Web.Script.Serialization;
名称空间AWS_TranslateTextTest
{
类AWS_TranslateText
{
//用你自己的价值观来代替它
const string AccessKey=“AKI\u ADD\u YOUR\u AccessKey”;
const string SecretKey=“添加您的SecretKey”;
静态void Main()
{
尝试
{
string text=“将此文本从英语翻译为德语。”;
字符串sourceLang=“en”;
字符串targetLang=“de”;
字符串responseText=TranslateText(text、sourceLang、targetLang);
JObject json=JObject.Parse(responseText);
string translatedText=“;//从json或responseText读取响应
if(json.ToString()包含(“TranslatedText”)){
//要访问“点”表示法中的属性,请使用动态对象
动态obj=json;
translatedText=obj.translatedText.Value;
WriteLine(“TranslatedText为:{0}”,TranslatedText);
}
否则{
Console.WriteLine(“响应中未找到TranslatedText.”);
抛出新异常(json.ToString());
}
}
捕获(WebException ex)
{
控制台写入线(例如消息);
如果(例如响应!=null){
foreach(ex.Response.Headers中的字符串头)
{
WriteLine(“{0}:{1}”,header,ex.Response.Headers[header]);
}
使用(var responseStream=ex.Response.GetResponseStream())
{
if(responseStream!=null)
{
使用(var streamReader=newstreamreader(responseStream))
{
Console.WriteLine(streamReader.ReadToEnd());
}
}
}    }
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
}           
}
私有静态字符串TranslateText(字符串文本、字符串源语言、字符串目标语言)
{
var date=DateTime.UtcNow;
常量字符串算法=“AWS4-HMAC-SHA256”;
常量字符串regionName=“eu-west-1”;
常量字符串serviceName=“translate”;
const string method=“POST”;
常量字符串canonicalUri=“/”;
常量字符串canonicalQueryString=“”;
常量字符串x_amz_target_header=“AWSShineFrontendService_20170701.TranslateText”;
const string contentType=“应用程序/x-amz-json-1.1”;
常量字符串主机=serviceName+“+regionName+”.amazonaws.com”;
var obj=新
{
SourceLanguageCode=sourceLang,
TargetLanguageCode=targetLang,
文本=文本
};
var requestPayload=newJavaScriptSerializer().Serialize(obj);
var hashedRequestPayload=HexEncode(Hash(ToBytes(requestPayload));
var dateStamp=日期.ToString(“yyyyMMdd”);
var requestDate=date.ToString(“yyyyMMddTHHmmss”)+“Z”;
var credentialScope=string.Format(“{0}/{1}/{2}/aws4_请求”,日期戳,区域名称,服务名称);
var bytes=ToBytes(请求有效负载);
var headers=新的SortedDictionary
{
{“内容长度”,bytes.length.ToString()},
{“内容类型”,内容类型},
{“主机”,主机},
{“x-amz-date”,requestDate},
{“x-amz-target”,x_-amz_-target_头}
};
字符串规范标头=
string.Join(“\n”,headers.Select(x=>x.Key.ToLowerInvariant()+”:“+x.Value.Trim())+”\n”;
字符串签名头=
string.Join(“;”,headers.Select(x=>x.Key.ToLowerInvariant());
//任务1:为签名版本4创建规范请求
var canonicalRequest=method+'\n'+canonicalUri+'\n'+canonicalQueryString+
'\n'+canonicalHeaders+'\n'+signedHeaders+'\n'+hashedRequestPayload;
var hashedCanonicalRequest=HexEncode(Hash(ToBytes(canonicalRequest));
//任务2:为签名版本4创建要签名的字符串
//StringToSign=Algorit
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web.Script.Serialization;

namespace AWS_TranslateTextTest
{
    class AWS_TranslateText
    {

        // Replace this with your own values
        const string AccessKey = "AKI_ADD_YOUR_ACCESSKEY";
        const string SecretKey = "ADD_YOUR_SECRETKEY";

        static void Main()
        {
                try
            {
                    string text = "Translate this text from English to German.";
                    string sourceLang = "en";
                    string targetLang = "de";

                    string responseText = TranslateText(text, sourceLang, targetLang);

                    JObject json = JObject.Parse(responseText);

                    string translatedText = ""; // to do read response  from json or responseText

                    if (json.ToString().Contains("TranslatedText")){
                        //To access to the properties in "dot" notation use a dynamic object
                        dynamic obj = json;
                        translatedText = obj.TranslatedText.Value;
                        Console.WriteLine("TranslatedText is: {0}", translatedText);
                    }
                    else{
                        Console.WriteLine("TranslatedText not found in response.");
                        throw new Exception(json.ToString());
                    }
            }
            catch (WebException ex)
            {
               Console.WriteLine(ex.Message);
                    if (ex.Response != null){
                foreach (string header in ex.Response.Headers)
                {
                    Console.WriteLine("{0}: {1}", header, ex.Response.Headers[header]);
                }
                using (var responseStream = ex.Response.GetResponseStream())
                {
                    if (responseStream != null)
                    {
                        using (var streamReader = new StreamReader(responseStream))
                        {
                            Console.WriteLine(streamReader.ReadToEnd());
                        }
                    }
                }    }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }           
        }


          private static string TranslateText(string text, string sourceLang, string targetLang)
        {
            var date = DateTime.UtcNow;

            const string algorithm = "AWS4-HMAC-SHA256";
            const string regionName = "eu-west-1";
            const string serviceName = "translate";
            const string method = "POST";
            const string canonicalUri = "/";    
            const string canonicalQueryString = "";  
            const string x_amz_target_header = "AWSShineFrontendService_20170701.TranslateText";

                const string contentType = "application/x-amz-json-1.1";


            const string host = serviceName + "." + regionName + ".amazonaws.com";

            var obj = new
            {
                     SourceLanguageCode = sourceLang,
                     TargetLanguageCode = targetLang,
                     Text = text
            };
            var requestPayload = new JavaScriptSerializer().Serialize(obj);

            var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));

            var dateStamp = date.ToString("yyyyMMdd");
            var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
            var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);

                var bytes = ToBytes(requestPayload);


                var headers = new SortedDictionary<string, string>
            {

                     {"content-length", bytes.Length.ToString()},
                     {"content-type", contentType},
                {"host", host},
                     {"x-amz-date", requestDate},
                     {"x-amz-target", x_amz_target_header}
            };

            string canonicalHeaders =
                string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";

                string signedHeaders =
                string.Join(";", headers.Select(x => x.Key.ToLowerInvariant() ));

            // Task 1: Create a Canonical Request For Signature Version 4
            var canonicalRequest = method + '\n' + canonicalUri + '\n' + canonicalQueryString +
                                   '\n' + canonicalHeaders + '\n' + signedHeaders + '\n' + hashedRequestPayload;

            var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));


            // Task 2: Create a String to Sign for Signature Version 4
            // StringToSign  = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HashedCanonicalRequest

            var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}", algorithm, requestDate, credentialScope,
                hashedCanonicalRequest);


            // Task 3: Calculate the AWS Signature Version 4

            // HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20130913"),"eu-west-1"),"tts"),"aws4_request")
            byte[] signingKey = GetSignatureKey(SecretKey, dateStamp, regionName, serviceName);

            // signature = HexEncode(HMAC(derived-signing-key, string-to-sign))
            var signature = HexEncode(HmacSha256(stringToSign, signingKey));


            // Task 4: Prepare a signed request
            // Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature

            var authorization =
                string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
                    algorithm, AccessKey, dateStamp, regionName, serviceName, signedHeaders, signature);

            // Send the request
                string endpoint = "https://" + host; // + canonicalUri ;


            var webRequest = WebRequest.Create(endpoint);

            webRequest.Method = method;
            webRequest.Timeout = 20000;
            webRequest.ContentType = contentType;
            webRequest.Headers.Add("X-Amz-Date", requestDate);
            webRequest.Headers.Add("Authorization", authorization);
                webRequest.Headers.Add("X-Amz-Target", x_amz_target_header);    

            webRequest.ContentLength = bytes.Length; 

            using (Stream newStream = webRequest.GetRequestStream())
            {
                newStream.Write(bytes, 0, bytes.Length);
                newStream.Flush();
            }

            var response = (HttpWebResponse)webRequest.GetResponse();

            using (Stream responseStream = response.GetResponseStream())
            {
                if (responseStream != null)
                {

                          using (var streamReader = new StreamReader(responseStream))
                          {
                                string res = streamReader.ReadToEnd();
                                return res;
                          }
                }
            }



            return null;
        }

        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));
        }
    }
}