【问题标题】:Azure Storage Queue via REST API c# using Shared Key AuthenticationAzure Storage Queue via REST API c# using Shared Key Authentication
【发布时间】:2021-07-09 16:47:40
【问题描述】:

我正在尝试使用 REST API 调用 Azure 存储队列,但出现错误

在 HTTP 请求中找到的 MAC 签名 'UCiypkoySXueF4scXt+EqQESf5VXmAVLJUA93+3W10M=' 与任何不一样 计算签名。服务器使用以下字符串进行签名:'POST 文本/纯文本

我的 C# 代码是

  var Client = new HttpClient();
        var RequestDateString = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);

        if (Client.DefaultRequestHeaders.Contains("x-ms-date"))
            Client.DefaultRequestHeaders.Remove("x-ms-date");
        Client.DefaultRequestHeaders.Add("x-ms-date", RequestDateString);


        var StorageAccountName = "storaxxxxxxxsnd";
        var StorageKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==";
        String urlPath = String.Format("{0}/messages", "splitator");
        Uri uri = new Uri(string.Format("https://{0}.queue.core.windows.net/", StorageAccountName) + urlPath);

        if (Client.DefaultRequestHeaders.Contains("Authorization"))
            Client.DefaultRequestHeaders.Remove("Authorization");

        var canonicalizedStringToBuild = string.Format("{0}\n{1}", RequestDateString, $"/{StorageAccountName}/{uri.AbsolutePath.TrimStart('/')}");
        string signature;
        using (var hmac = new HMACSHA256(Convert.FromBase64String(StorageKey)))
        {
            byte[] dataToHmac = Encoding.UTF8.GetBytes(canonicalizedStringToBuild);
            signature = Convert.ToBase64String(hmac.ComputeHash(dataToHmac));
        }

        string authorizationHeader = string.Format($"{StorageAccountName}:" + signature);
        Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", authorizationHeader);
        Client.DefaultRequestHeaders.Accept.Clear();
        
        Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
        if (Client.DefaultRequestHeaders.Contains("x-ms-version"))
            Client.DefaultRequestHeaders.Remove("x-ms-version");

        Client.DefaultRequestHeaders.Add("x-ms-version", "2015-12-11");

        // if (httpMethod == HttpMethod.Delete || httpMethod == HttpMethod.Put)
        //  {
        //    if (Client.DefaultRequestHeaders.Contains("If-Match"))
        //       Client.DefaultRequestHeaders.Remove("If-Match");
        // Currently I'm not using optimistic concurrency :-(
        try
        {
            //Client.DefaultRequestHeaders.Add("If-Match", "*");
            var stringContent = new StringContent("TESTAUTH", Encoding.UTF8, "text/plain");
           var response= Client.PostAsync(uri, stringContent);
            var resu=response.Result;
            
        }
        catch(Exception ex)
        {

        }

我不确定我错过了什么。我尝试了各种组合,但都失败了。

我也试过微软推荐的 stringToSign 公式

I tried  using canonical headers too


        string signature;
     
        var stringTosign =  "POST\n" + "\n" + "\n" + "1024" + "\n" + "\n" + "text/plain\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + dateInRfc1123Format + "/xxxxxx/splitator/messages";

       var hmac = new HMACSHA256(Convert.FromBase64String(accountKey));
       var headerval= accountName + ":" + Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringTosign)));
        Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", headerval);
        Client.DefaultRequestHeaders.Accept.Clear();
    

【问题讨论】:

  • 问题是你如何构建你的canonicalizedStringToBuild。请在此处查看说明:docs.microsoft.com/en-us/rest/api/storageservices/…。另外,你为什么不使用 SDK?
  • 我需要使用 REST API 而不添加任何额外的 NuGet 包或基于天蓝色的库。
  • 几件事:1)您能否使用您使用的完整最新代码更新您的问题。这将使事情变得更容易,并且 2)检查错误响应的响应正文。这应该告诉您存储服务使用的要签名的字符串。您可以将其与您的字符串进行比较以签署值,以确定您在哪里犯了错误。

标签: c# azure-functions azure-storage storage-access-api


【解决方案1】:

我在您的代码中解决了这个问题,现在它可以正常工作了。请试一试:

namespace ConsoleApp25
{
    class Program
    {
        static void Main(string[] args)
        {
            var Client = new HttpClient();
           
            var StorageAccountName = "yy1";
            var StorageKey = "xxxx";
            var apiversion = "2020-02-10";
            var queue_name = "myqueue2";
            String urlPath = String.Format("{0}/messages", queue_name);
            Uri uri = new Uri(string.Format("https://{0}.queue.core.windows.net/{1}", StorageAccountName, urlPath));

            //define a message to send
            string raw_message = "TESTAUTH is ok";

            //to send the message to the queue storage, the raw message must be formatted as below
            string queue_message = $"<QueueMessage><MessageText>{raw_message}</MessageText></QueueMessage>";

            //define the content type
            string content_type = "text/plain; charset=utf-8";

            //define date
            var RequestDateString = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);

            string StringToSign = String.Format("POST\n"
                + "\n" // content encoding
                + "\n" // content language
                + queue_message.Length + "\n" // content length
                + "\n" // content md5
                + content_type +"\n" // content type
                + "\n" // date
                + "\n" // if modified since
                + "\n" // if match
                + "\n" // if none match
                + "\n" // if unmodified since
                + "\n" // range
                + "x-ms-date:" + RequestDateString + "\nx-ms-version:" + apiversion + "\n" // headers
                + "/{0}/{1}/{2}", StorageAccountName, queue_name, "messages"); //url

            string auth = SignThis(StringToSign, StorageKey, StorageAccountName);

            //define authorization header
            if (Client.DefaultRequestHeaders.Contains("Authorization"))
                Client.DefaultRequestHeaders.Remove("Authorization");

            Client.DefaultRequestHeaders.Add("Authorization", auth);

            Client.DefaultRequestHeaders.Accept.Clear();

            //define x-ms-version header
            Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
            if (Client.DefaultRequestHeaders.Contains("x-ms-version"))
                Client.DefaultRequestHeaders.Remove("x-ms-version");

            Client.DefaultRequestHeaders.Add("x-ms-version", apiversion);

            //define the x-ms-date header
            if (Client.DefaultRequestHeaders.Contains("x-ms-date"))
                Client.DefaultRequestHeaders.Remove("x-ms-date");
            Client.DefaultRequestHeaders.Add("x-ms-date", RequestDateString);

            try
            {
                var stringContent = new StringContent(queue_message, Encoding.UTF8, "text/plain");
                var response = Client.PostAsync(uri, stringContent);
                var resu = response.Result;
               
            }
            catch (Exception ex)
            {

            }

            Console.WriteLine("**completed**");
            Console.ReadLine();
        }

        private static String SignThis(String StringToSign, string Key, string Account)
        {
            String signature = string.Empty;
            byte[] unicodeKey = Convert.FromBase64String(Key);
            using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
            {
                Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
                signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
            }

            String authorizationHeader = String.Format(
                  CultureInfo.InvariantCulture,
                  "{0} {1}:{2}",
                  "SharedKey",
                  Account,
                  signature);

            return authorizationHeader;
        }

    }
}

如果你不想生成shared key,因为它不容易,你可以在rest api中使用sas token进行身份验证。

【讨论】:

  • 不错的伊万。万分感谢。干杯
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 2020-05-16
  • 2023-02-18
  • 2022-12-01
  • 1970-01-01
  • 2019-01-02
  • 1970-01-01
相关资源
最近更新 更多