Azure Blob 403 Forbidden using SAS to create and use BlobContainer

时间:2016-04-21 22:21:48

标签: c# azure azure-storage-blobs

I am using code copied and modified from this MSDN article:

MSDN article about Azure SAS usage

I am using the Azure Storage Emulator and can generate the SAS. Here is an example:

http://127.0.0.1:10000/devstoreaccount1/7373df60-ad5f-462e-a55d-15c21c2de0e1?sv=2015-04-05&sr=c&si=ac&sig=bQAsuNUsj6MycN0aTyurVugHBMOlokwsXJA9xv7VeiU%3D

I can use the Edge browser to list the blob container by appending:

&comp=list&restype=container

so that my link now looks like this:

http://127.0.0.1:10000/devstoreaccount1/7373df60-ad5f-462e-a55d-15c21c2de0e1?sv=2015-04-05&sr=c&si=ac&sig=bQAsuNUsj6MycN0aTyurVugHBMOlokwsXJA9xv7VeiU%3D&comp=list&restype=container

This makes me think that the SAS is correct and the storage emulator is working. The browser displays the info for the container and all of the blobs in it.

I can check the storage emulator log and see this message:

4/21/2016 3:56:10 PM [AuthorizationFailure] [ActivityId=a79d230e-6596-4e43-8ef9-58943ee91b58] Unauthorized: Signed access not supported for this request with FailureReason InvalidOperationSAS

Here is the code that I use to create the SAS:

    String policyName = "ac";

var storedPolicy = new SharedAccessBlobPolicy()
{
   SharedAccessExpiryTime = DateTime.UtcNow.AddHours(expireHours),
   Permissions = SharedAccessBlobPermissions.Read |
   SharedAccessBlobPermissions.List |
   SharedAccessBlobPermissions.Delete
};

var permissions = container.GetPermissions();

permissions.SharedAccessPolicies.Clear();

permissions.SharedAccessPolicies.Add(policyName, storedPolicy);

container.SetPermissions(permissions);

string sasContainerToken = container.GetSharedAccessSignature(null, policyName);

// Return the URI string for the container, including the SAS token.

return container.Uri + sasContainerToken;

And here is the code that I use to create the CloudBlobContainer using the SAS:

CloudBlobContainer container = new CloudBlobContainer( new Uri(sas) );   // AzureBlob.GetBlobContainer(sas); // gets a new container

if ( ! container.Exists() ) // throws exception
{
   throw new Exception("Container no longer exists for sas " + sas);
}

container.FetchAttributes();

Here is the exception:

   Microsoft.WindowsAzure.Storage.StorageException: The remote server returned an error: (403) Forbidden. ---> System.Net.WebException: The remote server returned an error: (403) Forbidden.
   at System.Net.HttpWebRequest.GetResponse()
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) in c:\\Program Files (x86)\\Jenkins\\workspace\\release_dotnet_master\\Lib\\ClassLibraryCommon\\Core\\Executor\\Executor.cs:line 677
   --- End of inner exception stack trace ---
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) in c:\\Program Files (x86)\\Jenkins\\workspace\\release_dotnet_master\\Lib\\ClassLibraryCommon\\Core\\Executor\\Executor.cs:line 604
   at Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer.Exists(Boolean primaryOnly, BlobRequestOptions requestOptions, OperationContext operationContext) in c:
    \\Program Files (x86)\\Jenkins\\workspace\\release_dotnet_master\\Lib\\ClassLibraryCommon\\Blob\\CloudBlobContainer.cs:line 1406
   at Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer.Exists(BlobRequestOptions requestOptions, OperationContext operationContext) in c:\\Program Files (x86)\\Jenkins\\workspace\\release_dotnet_master\\Lib\\ClassLibraryCommon\\Blob\\CloudBlobContainer.cs:line 1393

Here is a link to an article that seems to be a distant relative.

SO question about SAS

2 个答案:

答案 0 :(得分:3)

您的代码失败的原因是您创建的内容是Service Shared Access Signature (Service SAS)而不是Account Shared Access Signature (Account SAS)。要创建blob容器,您需要使用Account SAS而不是Service SAS。

从此页面:https://msdn.microsoft.com/en-us/library/azure/ee395415.aspx

  

2015-04-05版本中引入的帐户级SAS。帐户   SAS委派对一个或多个存储中的资源的访问权限   服务。通过服务SAS提供的所有操作也是   可通过SAS帐户获取。此外,使用帐户SAS,您   可以委派对适用于给定服务的操作的访问权限,例如   作为获取/设置服务属性和获取服务统计信息。 你也可以   委托访问blob上的读,写和删除操作   容器,表,队列和不允许的文件共享   使用SAS服务。有关更多信息,请参阅构建帐户SAS   有关帐户SAS的信息。

以下是创建帐户SAS并使用它创建blob容器的示例代码:

        var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
        var blobClient = storageAccount.CreateCloudBlobClient();
        var blobSharedAccessPolicy = new SharedAccessAccountPolicy()
        {
            Services = SharedAccessAccountServices.Blob,
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1),
            Permissions = SharedAccessAccountPermissions.Write,
            ResourceTypes = SharedAccessAccountResourceTypes.Container
        };
        var sas = storageAccount.GetSharedAccessSignature(blobSharedAccessPolicy);
        var containerName = "created-using-account-sas";
        var containerUri = string.Format("{0}{1}", storageAccount.BlobEndpoint, containerName);
        var blobContainer = new CloudBlobContainer(new Uri(containerUri), new StorageCredentials(sas));
        blobContainer.Create();
        Console.WriteLine("Container created....");

答案 1 :(得分:0)

我不确定您到底遇到了什么,但这是我根据https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-shared-access-signature-part-2/

的信息整理的内容

也许将我的代码与我的代码进行比较,看看可能有什么不同

public string CreateSharedAccessSignature(string blobUri, int timeout, TimeUnitType timeUnit)
    {
        try
        {
            var uri = new Uri(blobUri);
            var cloudBlob = _context.CloudBlobClient.GetBlobReferenceFromServer(uri);

            if (!cloudBlob.Exists())
            {
                throw new StorageException("Blob does not exist");
            }

            var sasConstraints = new SharedAccessBlobPolicy
            {
                SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),
                Permissions = SharedAccessBlobPermissions.Read
            };

            //The shared access signature will be valid immediately.
            switch(timeUnit)
            {
                case TimeUnitType.Days:
                    sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddDays(timeout);
                    break;
                case TimeUnitType.Hours:
                    sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(timeout);
                    break;
                case TimeUnitType.Minutes:
                    sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(timeout);
                    break;
                case TimeUnitType.Seconds:
                    sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddSeconds(timeout);
                    break;
            }

            //Generate the shared access signature on the blob, setting the constraints directly on the signature.
            string sasBlobToken = cloudBlob.GetSharedAccessSignature(sasConstraints);

            return cloudBlob.Uri + sasBlobToken;
        }
        catch(Exception ex)
        {
            //new RaygunClient().Send(ex);
            throw;
        }
    }