如何为同一个Azure Blob容器创建多个存储访问策略?

3

我已经阅读并尝试了https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-shared-access-signature-part-2/#part-1-create-a-console-application-to-generate-shared-access-signatures中的示例代码。

然后我将其应用到我的场景中。

我编写了一个工具,用于将合作伙伴的数据上传到Azure Blob存储中,然后它将被一些内部团队使用: YYYY-MM(容器)                 (DD-GUID)(前缀)                                 File1.zip                                 File2.zip ……

我为每个容器创建了两个策略: 1. 只允许合作伙伴写入Blob,不允许其他操作。 2. 允许我们的内部团队列出和读取(下载)容器中的所有Blob。

我的想法是只需将正确的策略交给相应的接收者即可;然而,我的实现效果不如预期。

我使用以下方法为每个容器创建了两个策略,当然每个策略都有正确的权限:

static void CreateSharedAccessPolicy(CloudBlobClient blobClient, CloudBlobContainer container, string policyName)
    {
        //Create a new stored access policy and define its constraints.
        SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
        {
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(10),
            Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List
        };

        //Get the container's existing permissions.
        BlobContainerPermissions permissions = new BlobContainerPermissions();

        //Add the new policy to the container's permissions.
        permissions.SharedAccessPolicies.Clear();
        permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
        container.SetPermissions(permissions);
    }

我首先创建了只写策略,然后再创建了读取和列出策略。我发现第一个策略似乎不起作用,所有内容都返回403 Forbidden,而对于第二个策略,只有列出blob文件能够正常工作,但是读取(我尝试下载blob文件但是得到了404 Not Found)无法正常工作。
看起来我在这里忽略了一些非常基本的东西。请您帮忙看看我的方法有什么问题。
我用来测试容器权限的代码,我还注意到Azure文档中提到的容器上的读取权限实际上并不能正常工作。在这里,我试图找到一种简单的方式,只需提供存储访问策略即可允许用户列出并下载容器中的所有blob文件,而不是为每个blob文件提供签名。:
static void UseContainerSAS(string sas) { // 使用提供的SAS尝试执行容器操作。

        //Return a reference to the container using the SAS URI.
        CloudBlobContainer container = new CloudBlobContainer(new Uri(sas));

        //Create a list to store blob URIs returned by a listing operation on the container.
        List<Uri> blobUris = new List<Uri>();

        try
        {
            //Write operation: write a new blob to the container. 
            CloudBlockBlob blob = container.GetBlockBlobReference("blobCreatedViaSAS.txt");
            string blobContent = "This blob was created with a shared access signature granting write permissions to the container. ";
            MemoryStream msWrite = new MemoryStream(Encoding.UTF8.GetBytes(blobContent));
            msWrite.Position = 0;
            using (msWrite)
            {
                blob.UploadFromStream(msWrite);
            }
            Console.WriteLine("Write operation succeeded for SAS " + sas);
            Console.WriteLine();
        }
        catch (StorageException e)
        {
            Console.WriteLine("Write operation failed for SAS " + sas);
            Console.WriteLine("Additional error information: " + e.Message);
            Console.WriteLine();
        }

        try
        {
            //List operation: List the blobs in the container, including the one just added.
            foreach (ICloudBlob blobListing in container.ListBlobs())
            {
                blobUris.Add(blobListing.Uri);
            }
            Console.WriteLine("List operation succeeded for SAS " + sas);
            Console.WriteLine();
        }
        catch (StorageException e)
        {
            Console.WriteLine("List operation failed for SAS " + sas);
            Console.WriteLine("Additional error information: " + e.Message);
            Console.WriteLine();
        }

        try
        {
            CloudBlockBlob blob = container.GetBlockBlobReference(blobUris[0].ToString());

            MemoryStream msRead = new MemoryStream();
            msRead.Position = 0;
            using (msRead)
            {
                blob.DownloadToStream(msRead);
                Console.WriteLine(msRead.Length);
            }
            Console.WriteLine("Read operation succeeded for SAS " + sas);
            Console.WriteLine();
        }
        catch (StorageException e)
        {
            Console.WriteLine("Read operation failed for SAS " + sas);
            Console.WriteLine("Additional error information: " + e.Message);
            Console.WriteLine();
        }
        Console.WriteLine();

        try
        {
            //Delete operation: Delete a blob in the container.
            CloudBlockBlob blob = container.GetBlockBlobReference(blobUris[0].ToString());
            blob.Delete();
            Console.WriteLine("Delete operation succeeded for SAS " + sas);
            Console.WriteLine();
        }
        catch (StorageException e)
        {
            Console.WriteLine("Delete operation failed for SAS " + sas);
            Console.WriteLine("Additional error information: " + e.Message);
            Console.WriteLine();
        }
    }

[tag:sas] 是用于编程/数据库语言SAS,而不是用于此特定用途。我认为 [tag:azure-storage-blobs] 是正确的标签,但如果我错了,请谅解并请应用正确的标签。谢谢! - Joe
尝试将共享访问策略的开始时间设置为 DateTime.UtcNow.AddMinutes(-5) - Brendan Green
SAS是Shared Access Signature的缩写,是Azure存储中使用的术语。我该如何将这个SAS与原始的区分开来?关于开始时间,如果您没有指定它,意味着您希望策略立即生效,这也是我想要的。 - Long Nguyen
1个回答

7

实际上,你后面的操作抹去了你在第一个操作中做的事情。为了避免这种情况发生,你应该读取容器中现有的权限,添加新的权限,然后将权限设置回容器。

以下是正确的代码示例:

static void CreateSharedAccessPolicy(CloudBlobClient blobClient, CloudBlobContainer container, string policyName)
{
    //Create a new stored access policy and define its constraints.
    SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
    {
        SharedAccessExpiryTime = DateTime.UtcNow.AddHours(10),
        Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List
    };

    //Get the container's existing permissions.
    BlobContainerPermissions permissions = container.GetPermissions();

    //Add the new policy to the container's permissions.
    permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
    container.SetPermissions(permissions);
}

如果您在读取Blob时遇到404错误的原因,请分享创建SAS策略的代码以及如何使用创建的SAS来读取Blob,以便我可以帮助您进行故障排除。

以下是一个创建SAS并使用它来读取Blob的代码示例:(您可以将stdout中的URL复制+粘贴到浏览器中直接尝试)

        var permissions = container.GetPermissions();
        var policy = new SharedAccessBlobPolicy
        {
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessExpiryTime = DateTime.UtcNow.AddYears(1),
        };

        string policyName = "read";
        permissions.SharedAccessPolicies.Add(policyName, policy);
        container.SetPermissions(permissions);
        string sas = container.GetSharedAccessSignature(null, policyName);
        var blobs = container.ListBlobs(null, true);
        Console.WriteLine("SAS = {0}", sas);
        Console.WriteLine("Blobs URLs with SAS:");

        foreach (var blob in blobs)
        {
            Console.WriteLine(blob.Uri.ToString() + sas);
        }

谢谢赵兴!你的示范代码可行,我也在我的原帖中添加了方法UseContainerSAS(string sas),这就是我试图下载blob的方法。无论如何,我在Azure文档中读到一些内容关于容器上的读取权限并不意味着人们将对属于此容器的所有blob都具有读取权限。你知道如何让人们能够下载所有blob而无需每个blob一个SAS吗?我不想将所有blob的SAS列表发送给我的客户,或者这是唯一的实现方式吗? - Long Nguyen
容器的读取权限确实意味着人们可以读取所有的 blob,但是你无法通过容器 SAS 访问这些 blob,可能存在某些问题。 - Zhaoxing Lu
如果你不介意任何人都能够读取数据的话,可以考虑使用公共读取访问容器。方法是调用 permissions.PublicAccess = BlobContainerPublicAccessType.Blob;和 container.SetPermissions(permissions); - Zhaoxing Lu
赵兴,这是一个链接,其中有一篇帖子同意我的观点,即容器级别的读取访问权限没有任何意义。http://gauravmantri.com/2013/02/13/revisiting-windows-azure-shared-access-signature/#comment-21224。我已经在代码中实现了,但它不起作用。你是否成功创建了具有这些访问权限(列表和读取)的容器并进行了测试,还是你只是猜测它应该可以工作? - Long Nguyen
我同意赵兴的代码,但是要小心。Azure存储容器只能有5个关联策略。所以,赵兴的代码在第6次执行时会抛出ArgumentOutOfRangeException异常。请参见这里:https://dev59.com/4W7Xa4cB1Zd3GeqPsa3Y - 1c1cle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接