问题描述
我对此进行了相当长的研究,但一直无法通过 .NET Core webapi 对存储帐户执行基本操作。
您应该了解以下内容:
- 允许 Blob 公共访问设置为“已禁用”(强烈 微软推荐)
- 帐户类型为 BlobStorage
- 必须通过共享密钥来授权对 Azure 存储的请求(我不喜欢 SAS)
我在我的项目中引用了 Azure.Storage.Blobs 包,并将其作为服务注入,如下所示:
services.AddSingleton(x => new BlobServiceClient(config.GetValue<string>("AzureBlobStorage")));
AzureBlobStorage
是我到存储帐户的连接字符串。
Task<Uri> UploadBlobAsync(string blobContainerName,Stream content,string contentType,string fileName);
Task<CustomBlobInfo> GetBlobAsync(string blobContainerName,string fileName);
Task<IEnumerable<string>> ListBlobsAsync(string blobContainerName);
Task DeleteBlobAsync(string blobContainerName,string fileName);
上传blob的过程如下:
-
我在我的 post man 中点击了以下 http 请求(方法:POST)
http://localhost:5000/api/blob/container/6735D6F0-8FC1-4C6E-B08C-FFBB5B29C4A1
uniqueidentifier 是我的存储帐户中的容器名称。
-
IFormFile file = Request.Form.Files[0]; if (file == null) { return BadRequest(); } string fileName = Guid.NewGuid().ToString().ToLower(); string containerName = blobContainerName.ToLower(); var result = await this.blobService.UploadBlobAsync( containerName,file.OpenReadStream(),file.ContentType,fileName); var toReturn = result.AbsoluteUri; return Ok(new { path = toReturn });
但是,我遇到了一个问题,我的代码抛出一个异常,说禁止公共访问
public async Task<Uri> UploadBlobAsync(string blobContainerName,string fileName)
{
var containerClient = GetContainerClient(blobContainerName); // <<<<< EXCEPTION
var blobClient = containerClient.GetBlobClient(fileName);
await blobClient.UploadAsync(content,new BlobHttpHeaders { ContentType = contentType });
return blobClient.Uri;
}
我的 GetContainerClient()
是一个私有方法,我用来检查容器是否存在,如果不存在,则创建一个容器
private BlobContainerClient GetContainerClient(string blobContainerName)
{
var containerClient = this.blobServiceClient.GetBlobContainerClient(blobContainerName);
containerClient.CreateIfNotExists(PublicAccesstype.Blob);
return containerClient;
}
到目前为止,很明显为什么我会收到此异常..因为公共访问级别已禁用..
Microsoft 文档说我需要生成一个以某种方式附加到我的请求的共享访问密钥..
private void GenerateSharedAccessKeyRequestHeader(string blobContainerName,string fileName,string contentType)
{
string storageKey = "key";
string storageAccount = "name";
string method = "PUT";
long contentLength = content.Length;
string requestUri = $"https://{storageAccount}.blob.core.windows.net/{blobContainerName}/{fileName}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
string Now = DateTime.UtcNow.ToString("R");
request.Method = method;
request.ContentType = contentType;
request.ContentLength = contentLength;
request.Headers.Add("x-ms-version","2015-12-11");
request.Headers.Add("x-ms-date",Now);
request.Headers.Add("x-ms-blob-type","BlockBlob");
request.Headers.Add("Authorization",AuthorizationHeader(method,Now,request,storageAccount,storageKey,blobContainerName,fileName));
}
private string AuthorizationHeader(string method,string Now,HttpWebRequest request,string storageAccount,string storageKey,string containerName,string blobName)
{
string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:{Now}\nx-ms-version:2015-12-11";
string urlResource = $"/{storageAccount}/{containerName}/{blobName}";
string stringToSign = $"{method}\n\n\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{headerResource}\n{urlResource}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(storageKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
String AuthorizationHeader = String.Format("{0} {1}:{2}","SharedKey",signature);
return AuthorizationHeader;
}
问题是我不确定在哪里注入这些请求标头以上传我的 blob 或创建容器,甚至从我的存储帐户中获取/列出/删除 blob?
public async Task<CustomBlobInfo> GetBlobAsync(string blobContainerName,string fileName)
{
var containerClient = GetContainerClient(blobContainerName);
var blobClient = containerClient.GetBlobClient(fileName);
var blobDownloadInfo = await blobClient.DownloadAsync();
return new CustomBlobInfo(blobDownloadInfo.Value.Content,blobDownloadInfo.Value.ContentType);
}
public async Task<IEnumerable<string>> ListBlobsAsync(string blobContainerName)
{
var containerClient = GetContainerClient(blobContainerName);
var items = new List<string>();
await foreach (var item in containerClient.GetBlobsAsync())
{
items.Add(item.Name);
}
return items;
}
public async Task DeleteBlobAsync(string blobContainerName,string fileName)
{
var containerClient = GetContainerClient(blobContainerName);
var blobClient = containerClient.GetBlobClient(fileName);
await blobClient.DeleteIfExistsAsync();
}
这应该很容易,但出于某种原因,我已经坚持了好几天了..
解决方法
您的 Blob 存储帐户设置为:
允许 Blob 公共访问设置为“已禁用”
然后您的代码通过 PublicAccessType.Blob
:
containerClient.CreateIfNotExists(PublicAccessType.Blob);
然后你得到一个例外:
抛出异常,表示禁止公开访问
在我看来,修复方法是:
- 删除 blob 的公共访问权限:
containerClient.CreateIfNotExists();
,或 - Enable blob public access for the storage account。
作为documented:
要授予匿名用户对容器及其 Blob 的读取访问权限,请首先允许对存储帐户进行公共访问,然后设置容器的公共访问级别。如果存储帐户的公共访问被拒绝,您将无法为容器配置公共访问。