【问题标题】:Azure v2 GetResponse fails to authenticate. Error 403: ForbiddenAzure v2 GetResponse 无法进行身份验证。错误 403:禁止
【发布时间】:2013-01-22 10:05:53
【问题描述】:

我正在将 Windows Azure 从 1.7 迁移(叹气)到版本 2,而我现在在使用旧的身份验证方式时遇到了一些问题。当我尝试执行下一个代码时(使用 Azure SDK 的旧实现)...

[...]

var policy = new SharedAccessBlobPolicy();
policy.SharedAccessStartTime = new DateTimeOffset(DateTime.UtcNow.AddMinutes(-5));
policy.SharedAccessExpiryTime = policy.SharedAccessStartTime.Value.AddMinutes(5);
policy.Permissions = SharedAccessBlobPermissions.Read;

var sas = blobContainer.GetSharedAccessSignature(policy)
var request = WebRequest.Create(string.Format("{0}/{1}{2}", containerUri, blobName, sas));
request.Method = "GET";
var headers = new NameValueCollection();
headers.Add("x-ms-blob-type", "BlockBlob");
request.Headers.Add(headers);
request.ContentLength = 0;

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

[...]

... GetResponse() 方法对我很生气,并抛出一个 WebException 说“服务器无法验证请求。确保 Authorization 标头的值正确形成,包括签名。 "

ResponseUri 是http://127.0.0.1:10000/devstoreaccount1/testcontainer/testBlob?sv=2012-02-12&st=2013-01-22T09.52.27Z&se=2013-01-22T09.57.29Z&sr=c&sp=r&sig=WxFfIg9NxKodH7zGjKRym7RuXd61F5jlG6ILtG1UYPg%3D,我觉得很好。我以为是 AccountKey 的问题,但在真实存储上尝试使用 Azure 门户提供的正确密钥时,我遇到了同样的问题。

是否需要为新的 REST API 完成任何属性或新的初始化?

更新:我已经尝试了@Gaurav Mantri 在他的回复中开发的控制台应用程序,但它仍然不适合我。所以,我怀疑这个问题可能取决于我机器上的意大利语本地化,或者与 Windows 8 相关的一些东西(在另一位同事的机器上,控制台应用程序也不能正常工作,同样的错误 403,被禁止!由GetResponse)。我注意到我们得到的 URI 与我在网上找到的每个示例都不同,所以我将开始和到期时间视为(例如)2013-01-22T09.52.27Z 而不是2013-01-22T09%3A52%3A27Z

【问题讨论】:

    标签: c# azure azure-blob-storage


    【解决方案1】:

    好的,我找到了问题所在。

    Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; 行添加到我的代码(或测试初始化​​程序)将解决问题。

    查看 WindowsAzure.Storage 源,当服务创建签名时,它使用格式字符串“yyyy-MM-ddTHH:mm:ssZ”,而不将 CultureInfo.InvariantCulture 作为参数传递给 ToString 方法。但是对于意大利区域设置,小时、分钟和秒之间的分隔符是点,而美国是两点。所以我的本地机器和远程机器创建了两个不同的签名,他们无法匹配。

    我将将此报告为错误(或问题),因为并非每个人都有相同的区域设置。

    【讨论】:

    • 太棒了!很高兴您能够找到问题的原因。
    【解决方案2】:

    对于 GET 操作,您不需要添加“x-ms-blob-type”请求标头。仅在上传 blob 时才需要。请删除以下代码后重试:

    var headers = new NameValueCollection();
    headers.Add("x-ms-blob-type", "BlockBlob");
    request.Headers.Add(headers);
    

    更新: 下面是使用 SAS URI 读取 blob 的完整代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Auth;
    using Microsoft.WindowsAzure.Storage.Blob;
    using System.Net;
    using System.IO;
    namespace ConsoleApplication26
    {
        class Program
        {
            static void Main(string[] args)
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
                CloudBlobContainer blobContainer = storageAccount.CreateCloudBlobClient().GetContainerReference("temp");
                //Create blob container.
                blobContainer.CreateIfNotExists();
                string blobContents = "Let's test SAS out :)";
                byte[] bytes = Encoding.UTF8.GetBytes(blobContents);
    
                string blobName = "sastest.txt";
                CloudBlockBlob blob = blobContainer.GetBlockBlobReference(blobName);
                //Upload blob
                using (MemoryStream ms = new MemoryStream(bytes))
                {
                    blob.UploadFromStream(ms);
                }
                //Get SAS Uri
                var sasUri = GetSasUrl(blobContainer, blobName);
                DownloadBlob(sasUri);
    
                Console.ReadLine();
    
            }
    
            static Uri GetSasUrl(CloudBlobContainer blobContainer, string blobName)
            {
                var policy = new SharedAccessBlobPolicy()
                {
                    SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),
                    SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5),
                    Permissions = SharedAccessBlobPermissions.Read,
                };
    
                var sas = blobContainer.GetSharedAccessSignature(policy);
                return new Uri(string.Format("{0}/{1}{2}", blobContainer.Uri, blobName, sas));
            }
    
            static void DownloadBlob(Uri sasUri)
            {
                var request = (HttpWebRequest)WebRequest.Create(sasUri);
                request.Method = "GET";
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    long responseContentLength = response.ContentLength;
                    byte[] fetchedContents = new byte[(int) responseContentLength];
                    using (var stream = response.GetResponseStream())
                    {
                        stream.Read(fetchedContents, 0, fetchedContents.Length);
                    }
                    string blobContents = Encoding.UTF8.GetString(fetchedContents);
                    Console.WriteLine("Blob Contents: " + blobContents);
                }
            }
        }
    }
    

    【讨论】:

    • 是的,我在发布示例之前已经尝试过:)感谢您指出它仅在 PUT 期间需要。
    • 应该先尝试自己编码 :)。更新了我原来的答案。
    • Uhrm,我已经尝试将您的程序作为单元测试(只是复制并粘贴它,使用您的辅助方法没有任何修改),但它一直在 GetResponse() 上抛出异常。我开始认为我的机器上有些东西不能正常工作。
    • 我能够模拟您遇到的问题。我认为问题出在代码中的以下行:policy.SharedAccessExpiryTime = policy.SharedAccessStartTime.Value.AddMinutes(5);如果您查看原始帖子中的 SAS URL(st & se 参数),差异是 5 分钟而不是 10 分钟。可能是因为 SharedAccessStartTime 和 SharedAccessExpiryTime 的类型是 DateTimeOffset 而不是以前版本中的 DateTime:msdn.microsoft.com/en-us/library/windowsazure/…
    • 不,两种方法我都试过了。几天前我遇到了关于 DateTimeOffset 的相同问题(使用 TableEntity 中的时间戳),所以我已经检查过了。
    【解决方案3】:

    我在尝试上传文件时遇到了同样的错误。我进行了一些搜索,但建议的解决方案都没有奏效。

    然后我检查了内部异常中的 http 响应对象,发现我不小心使用了完整的文件路径而不是文件名创建了 blob(c:\folder\folder\file.jpg 而不仅仅是 file.jpb) ,所以它试图上传到的 url 不存在。

    【讨论】:

      猜你喜欢
      • 2015-12-02
      • 1970-01-01
      • 2021-06-23
      • 2019-05-12
      • 1970-01-01
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      • 2016-05-16
      相关资源
      最近更新 更多