Rest 如何在C中使用SAS访问Azure blob#

Rest 如何在C中使用SAS访问Azure blob#,rest,azure,blob,Rest,Azure,Blob,当我尝试使用特别共享访问签名(SAS)创建/访问Azure blob时,我收到“远程服务器返回错误:(403)禁止”。错误。有人能帮我确定一下这个代码出了什么问题吗 // Calling this function from Main(). public void uploadToBlob() { string content = "Hello World - Content of the file"; string fileName =

当我尝试使用特别共享访问签名(SAS)创建/访问Azure blob时,我收到“远程服务器返回错误:(403)禁止”。错误。有人能帮我确定一下这个代码出了什么问题吗

    // Calling this function from Main().
    public void uploadToBlob()
    {
        string content = "Hello World - Content of the file";
        string fileName = "TestFile";
        UploadFileToAzureBlobStorage(content, fileName);
    }

    void UploadFileToAzureBlobStorage(string content, string fileName)
    {
        string storageKey = "SAS Key";
        string storageAccount = "Storage Account name";
        string containerName = "Container Name";
        string blobName = fileName;

        string method = "PUT";
        string sampleContent = content;
        int contentLength = Encoding.UTF8.GetByteCount(sampleContent);

        string requestUri = $"https://{storageAccount}.blob.core.windows.net/{containerName}/{blobName}";

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
        string now = DateTime.UtcNow.ToString("R");
        request.Method = method;
        request.ContentType = "text/plain; charset=UTF-8";
        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, containerName, blobName));

        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
        }

        using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
        {
            if (resp.StatusCode == HttpStatusCode.OK)
            { }
        }
    }

    public 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(Encoding.ASCII.GetBytes(storageKey));
        string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
        String AuthorizationHeader = String.Format("{0} {1}:{2}", "SharedKey", storageAccount, signature);
        return AuthorizationHeader;
    }

当您使用帐户密钥时,需要上面使用的代码。此时,您需要在请求中计算并包括
授权
头。如果您使用的是
共享访问签名(SAS)
令牌,则不需要执行所有这些操作,因为SAS令牌已经包含授权信息

假设您的SAS令牌是有效的,并且包含上载文件的适当权限,那么您的代码将变得非常简单。请参阅下面的修改代码:

void UploadFileToAzureBlobStorage(string content, string fileName)
{
    string sasToken = "SAS Key";
    string storageAccount = "Storage Account name";
    string containerName = "Container Name";
    string blobName = fileName;

    string method = "PUT";
    string sampleContent = content;
    int contentLength = Encoding.UTF8.GetByteCount(sampleContent);

    string requestUri = $"https://{storageAccount}.blob.core.windows.net/{containerName}/{blobName}?{sasToken}";

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
    request.Method = method;
    request.ContentType = "text/plain; charset=UTF-8";
    request.ContentLength = contentLength;
    request.Headers.Add("x-ms-blob-type", "BlockBlob");

    using (Stream requestStream = request.GetRequestStream())
    {
        requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
    }

    using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
    {
        if (resp.StatusCode == HttpStatusCode.OK)
        { }
    }
}

我不知道这是否会直接起作用,因为我更改了connectionstring之外的一些内容。但也许会有帮助

请注意,在本例中,我将返回定义了头的映像路径,因为不需要将映像下载到服务器,最好直接交付到客户端

    public static string ChaveStringConexao { get; set; }        


    public static string ObterUrlTemporaria(string container, string nomeBlob, string nomeOriginal, bool paraDownload = false)
    {
        var blob = InstanciaContainer(container).GetBlockBlobReference(nomeBlob);
        var sasToken = string.Empty;

        var sasPolicy = new SharedAccessBlobPolicy
        {
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-15),
            SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30)
        };

        var _sasHeader = new SharedAccessBlobHeaders
        {
            ContentDisposition = $"attachment; filename={nomeOriginal}"
        };

        if (paraDownload)
        {
            sasToken = blob.GetSharedAccessSignature(sasPolicy, _sasHeader);
        }
        else
        {
            sasToken = blob.GetSharedAccessSignature(sasPolicy);
        }

        return new Uri(blob.Uri, sasToken).AbsoluteUri;
    }



    public static CloudBlobContainer InstanciaContainer(string container)
    {
        var storageAccount = CloudStorageAccount.Parse(ChaveStringConexao);
        var blobClient = storageAccount.CreateCloudBlobClient();
        var blobContainer = blobClient.GetContainerReference(container);

        return blobContainer;
    }
网络配置的连接字符串示例:

<add name="AzureArmazenamento" connectionString="DefaultEndpointsProtocol=https;AccountName=*****;AccountKey=ZO78t1NKuiW32kKTBlm6bWRohREzYpmokpuFI4N**********************;EndpointSuffix=core.windows.net" />
var cnn = ConfigurationManager.ConnectionStrings["AzureArmazenamento"].ConnectionString;
AzureUtilitario.ChaveStringConexao = cnn;

var url = AzureUtilitario.ObterUrlTemporaria(container, file.key, file.OriginalName, download);
    public static bool Salvar(string container, string nomeBlob, byte[] arquivo)
    {
        var blockBlob = InstanciaContainer(container).GetBlockBlobReference(nomeBlob);

        blockBlob.Properties.ContentType = Path.GetExtension(nomeBlob).ConverteParaContentType();

        using (var stream = new MemoryStream(arquivo))
        {
            blockBlob.UploadFromStream(stream);

            return true;
        }
    }
对于上传,您不需要任何不同。SAS问题在返回文件时向您说明:

<add name="AzureArmazenamento" connectionString="DefaultEndpointsProtocol=https;AccountName=*****;AccountKey=ZO78t1NKuiW32kKTBlm6bWRohREzYpmokpuFI4N**********************;EndpointSuffix=core.windows.net" />
var cnn = ConfigurationManager.ConnectionStrings["AzureArmazenamento"].ConnectionString;
AzureUtilitario.ChaveStringConexao = cnn;

var url = AzureUtilitario.ObterUrlTemporaria(container, file.key, file.OriginalName, download);
    public static bool Salvar(string container, string nomeBlob, byte[] arquivo)
    {
        var blockBlob = InstanciaContainer(container).GetBlockBlobReference(nomeBlob);

        blockBlob.Properties.ContentType = Path.GetExtension(nomeBlob).ConverteParaContentType();

        using (var stream = new MemoryStream(arquivo))
        {
            blockBlob.UploadFromStream(stream);

            return true;
        }
    }

对于存储密钥,您使用的是帐户密钥还是SAS令牌?另外,您有响应头吗?@Guaurav Mantri,我在这里传递SAS令牌。@Cam Soper,下面是响应:AuthenticationFailedServer无法验证请求。确保包括签名在内的授权标头的值格式正确。RequestId:d4af7fcf-001e-0041-7532-4127e3000000时间:2017-10-09T19:10:06.7310979ZRequest日期标题太旧:“2017年10月9日星期一17:40:52 GMT”它工作起来很有魅力,感谢Gaurav的建议!!感谢您的输入Leandro,您的示例还为我提供了一些如何使代码正常工作的想法。