【问题标题】:Windows azure REST API to List containers issueWindows azure REST API 列出容器问题
【发布时间】:2015-09-26 18:16:34
【问题描述】:

我正在尝试列出我的 Windows azure 存储帐户中的容器。但我遇到了一个异常
“远程服务器返回错误:(403) 服务器无法验证请求。确保 Authorization 标头的值格式正确,包括签名..”

但是我已经按照给出的说明包含了签名,有人发现我的代码有什么错误吗?

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(
                System.Globalization.CultureInfo.InvariantCulture,
                "{0} {1}:{2}",
                "SharedKey",
                Account,
                signature);
            return authorizationHeader;
        }
        static void ListContainers()
        {
            Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
            string Key = @"MyStorageAccountKey";
            string Account = @"MyStorageAccountName";

            DateTime dt = DateTime.UtcNow;

            string dataStr = dt.ToString ("R",System.Globalization.CultureInfo.InvariantCulture);
            string StringToSign = String.Format("GET\n"
                + "\n" // content encoding
                + "\n" // content language
                + "\n" // content length
                + "\n" // content md5
                + "\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:" + dataStr + "\nx-ms-version:2014-02-14\n" // headers
                + "/{0}\ncomp:list", Account);

            string auth = SignThis(StringToSign, Key, Account);
            string method = "GET";
            string urlPath = string.Format ("https://{0}.blob.core.windows.net/?comp=list", Account);
            Uri uri = new Uri(urlPath);
            HttpWebRequest reque = (HttpWebRequest)WebRequest.Create(uri);
            reque.Method = method;
            reque.Headers.Add("Authorization", auth);
            reque.Headers.Add("x-ms-date",dataStr);
            reque.Headers.Add("x-ms-version", "2014-02-14");

            using (HttpWebResponse response = (HttpWebResponse) reque.GetResponse ()) {
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    string text = reader.ReadToEnd();
                }
            }
        }

Edit : String i 用于生成签名

GET

x-ms-date:Tue, 14 Jul 2015 18:38:16 GMT
x-ms-version:2014-02-14
/MyStorageAccountName/
comp:list

编辑:我收到了异常响应:

<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:2fc74ef8-0001-0083-2664-be8850000000
Time:2015-07-14T18:38:18.0831721Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request '5rqWNl2i8kuZF6haCRqFr1S0viOM9eLjz4L/zU6GCsg=' is not the same as any computed signature. Server used following string to sign: 'GET

x-ms-date:Tue, 14 Jul 2015 18:38:16 GMT
x-ms-version:2014-02-14
/MyStorageAccountName/
comp:list'.</AuthenticationErrorDetail></Error>

最终编辑:在进行了 gauvrav 指定的所有更改后,我发现我使用的 storagekey 错误,更换正确的后,它工作正常。

此错误可能还有其他变化:请参考link

【问题讨论】:

  • 错误响应应包含用于对所使用的存储服务进行签名的字符串,因此您可以使用它来验证您的字符串签名中是否缺少某些内容。
  • 谢谢,你能解释一下如何获取存储服务的“string-to-sign”的值吗?
  • @SerdarOzler-Microsoft 的意思是,如果您运行代码并让 Fiddler 运行(或通过解析您得到的 WebException 的响应来检查错误),您将在错误消息中看到使用的 StringToSign由服务器。您可以将其与您的 StringToSign 进行比较,以查看不匹配的内容。我用这个技巧在你的代码中找到了问题。

标签: c# asp.net azure azure-storage azure-blob-storage


【解决方案1】:

请将您的StringToSign 更改为:

        string StringToSign = String.Format("GET\n"
            + "\n" // content encoding
            + "\n" // content language
            + "\n" // content length
            + "\n" // content md5
            + "\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:" + dataStr + "\nx-ms-version:2014-02-14\n" // headers
            + "/{0}/\ncomp:list", Account);//Notice an extra "/" after "{0}"

帐户名占位符后缺少/(上面代码中的最后一行)。完成此操作后,您应该能够看到以 XML 格式返回的容器列表。

【讨论】:

  • 感谢您指点 gaurav。我改变了它,得到同样的错误。我想还有其他错误吗?
  • 嗯...这很奇怪。我刚刚尝试过,它对我来说非常好用。这是我的代码副本:pastebin.com/KusuaqPS。您可以在 Fiddler 中运行您的代码并跟踪请求/响应并在此处分享吗? 403 错误的另外两个可能原因是 - 1) 帐户密钥不正确 2) 计算机上的时钟速度很慢(比如说超过 15 - 20 分钟)。也请检查这些。
  • 您的回复给了很大希望。我以前没有尝试过 fiddler,将尝试并尽快回复您。感谢您的回复。
  • :)。如果您没有 Fiddler,请尝试此处的代码:pastebin.com/VB0cYALU。我已经包含了获取 WebException 中返回的错误字符串的代码。关于你的问题,不是特别的。 dataStr 以 GMT 显示时间,如果您不在同一时区,它将与您计算机的日期时间不同。
  • 谢谢。您是否也可以将根据您的代码计算的StringToSign 也放入您的问题中?请同时使用最新的错误消息更新您的问题,以便我们可以将它们一起比较。
猜你喜欢
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 1970-01-01
  • 2013-02-15
  • 2015-10-15
  • 2018-02-09
  • 1970-01-01
相关资源
最近更新 更多