从Azure私有存储容器获取Blob流时遇权限错误求助
解决Azure Blob存储下载时的RequestFailedException权限错误
问题描述
我尝试从Azure私有存储容器获取Blob流,参考资料写了这个C#函数,但调用blobClient.Download()时抛出错误:
Azure.RequestFailedException: 'This request is not authorized to perform this operation using this permission...'
我确认传入的参数都是正确的,请问有没有简单的修复方案?
我的代码:
/// <summary> /// Get a blob out of storage. /// HEAVILY Based on Code from: /// https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-customer-provided-key /// </summary> /// <param name="iSA">Name of storage account</param> /// <param name="iSA_Key">Key for the storage account</param> /// <param name="iContainerName">Name of the container</param> /// <param name="iBlobName">Name of Blob to Get</param> /// <returns> /// A stream of the Blob /// </returns> public Stream getBlob( String iSA, String iSA_Key, String iContainerName, String iBlobName) { Uri accountUri = new Uri("https://" + iSA + ".blob.core.windows.net"); // https://stackoverflow.com/questions/16072709/converting-string-to-byte-array-in-c-sharp byte[] key = Encoding.ASCII.GetBytes(iSA_Key); // Specify the customer-provided key on the options for the client. BlobClientOptions options = new BlobClientOptions() { CustomerProvidedKey = new CustomerProvidedKey(key) }; // Create a client object for the Blob service, including options. BlobServiceClient serviceClient = new BlobServiceClient(accountUri, new DefaultAzureCredential(), options); // Create a client object for the container. // The container client retains the credential and client options. BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(iContainerName); // Create a new block blob client object. // The blob client retains the credential and client options. BlobClient blobClient = containerClient.GetBlobClient(iBlobName); Azure.Response<BlobDownloadInfo> myAR = blobClient.Download(); BlobDownloadInfo BDI = myAR.Value; return BDI.Content; }
问题分析与修复方案
你代码里的核心问题是混淆了存储账户的访问密钥和客户提供的加密密钥(CustomerProvidedKey),同时身份验证方式也不对:
- CustomerProvidedKey的用途:这个参数是用来解密那些用你自己提供的密钥加密的Blob,不是用来做存储账户的身份验证的。你错误地把存储账户的访问密钥(
iSA_Key)当成了加密密钥传入,这完全是两个不同的密钥。 - 身份验证方式错误:你用了
DefaultAzureCredential,但同时又有存储账户的访问密钥,应该直接用存储账户密钥来做身份验证,而不是依赖DefaultAzureCredential(它会尝试环境变量、托管身份等其他方式,这些可能没有权限访问你的私有容器)。
修复方案1:不需要客户提供的密钥加密(最常见场景)
如果你的Blob没有用自定义密钥加密,直接移除CustomerProvidedKey的设置,改用StorageSharedKeyCredential来做身份验证:
public Stream getBlob(string iSA, string iSA_Key, string iContainerName, string iBlobName) { Uri accountUri = new Uri($"https://{iSA}.blob.core.windows.net"); // 用存储账户密钥创建身份验证凭证 StorageSharedKeyCredential credential = new StorageSharedKeyCredential(iSA, iSA_Key); // 不需要设置CustomerProvidedKey(除非你的Blob是用自定义密钥加密的) BlobServiceClient serviceClient = new BlobServiceClient(accountUri, credential); BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(iContainerName); BlobClient blobClient = containerClient.GetBlobClient(iBlobName); var downloadResponse = blobClient.Download(); return downloadResponse.Value.Content; }
修复方案2:Blob确实用客户提供的密钥加密了
如果你的Blob是用自定义密钥加密的,那么你需要同时提供:
- 存储账户的访问密钥(用于身份验证)
- 单独的客户提供加密密钥(用于解密Blob)
修改代码如下:
public Stream getBlob(string iSA, string iSA_Key, string customerEncryptionKey, string iContainerName, string iBlobName) { Uri accountUri = new Uri($"https://{iSA}.blob.core.windows.net"); // 身份验证用存储账户密钥 StorageSharedKeyCredential credential = new StorageSharedKeyCredential(iSA, iSA_Key); // 解密用客户提供的加密密钥(注意:这个密钥和存储账户密钥不是同一个) byte[] encryptionKeyBytes = Convert.FromBase64String(customerEncryptionKey); // 通常加密密钥是Base64格式的,而不是ASCII BlobClientOptions options = new BlobClientOptions() { CustomerProvidedKey = new CustomerProvidedKey(encryptionKeyBytes) }; BlobServiceClient serviceClient = new BlobServiceClient(accountUri, credential, options); BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(iContainerName); BlobClient blobClient = containerClient.GetBlobClient(iBlobName); var downloadResponse = blobClient.Download(); return downloadResponse.Value.Content; }
额外提醒:
- 存储账户的访问密钥不要用
Encoding.ASCII.GetBytes处理,StorageSharedKeyCredential直接接受字符串形式的密钥即可。 - 客户提供的加密密钥通常是32字节的Base64字符串,要用
Convert.FromBase64String来转换,而不是ASCII编码,避免编码错误。
内容的提问来源于stack exchange,提问作者Shawn Eary
相关产品推荐
相关产品推荐

