Azure Blob Storage 403认证失败

4

我正在使用Azure Blob Storage来存储我的应用程序文件。对于公共容器,我已经轻松完成了存储,但是我在将它们变成私有时遇到了一些困难。

为了访问我的私有容器中的文件,我正在使用以下方法检索最终URL:

public static string GetBlobSasUri(string containerLocation, string blobName, string policyName = null)
        {
            string sasBlobToken;

            // Get a reference to a blob within the container.
            // Note that the blob may not exist yet, but a SAS can still be created for it.
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.
             ConnectionStrings["AzureConnection"].ConnectionString);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(containerLocation);
            CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

            if (policyName == null)
            {
                // Create a new access policy and define its constraints.
                // Note that the SharedAccessBlobPolicy class is used both to define the parameters of an ad-hoc SAS, and
                // to construct a shared access policy that is saved to the container's shared access policies.
                SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy()
                {
                    // When the start time for the SAS is omitted, the start time is assumed to be the time when the storage service receives the request.
                    // Omitting the start time for a SAS that is effective immediately helps to avoid clock skew.
                    SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
                    Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create
                };

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

                Console.WriteLine("SAS for blob (ad hoc): {0}", sasBlobToken);
                Console.WriteLine();
            }
            else
            {
                // Generate the shared access signature on the blob. In this case, all of the constraints for the
                // shared access signature are specified on the container's stored access policy.
                sasBlobToken = blob.GetSharedAccessSignature(null, policyName);

                Console.WriteLine("SAS for blob (stored access policy): {0}", sasBlobToken);
                Console.WriteLine();
            }

            // Return the URI string for the container, including the SAS token.
            return blob.Uri + sasBlobToken;
        }

但是当我尝试在浏览器中粘贴最终的URI时,总是会出现以下错误:
<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:96d18e26-0001-008e-7eb3-c88fcd000000 Time:2017-05-09T11:01:24.9128128Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rcw 2017-05-10T11:01:06Z /blob/mystorage/profiles/317ce29e-86c9-46d8-8579-8cbdaf385971pic.png 2016-05-31
</AuthenticationErrorDetail>
</Error>

你知道为什么吗?

更新: 连接字符串:

<add name="AzureConnection" connectionString="DefaultEndpointsProtocol=https;AccountName=mystorage;AccountKey=5Z+lqPDdRDdlVwSW6kA3iOIb8jUjJkib6A/gAQ8UeqcgPcsW1Do0NbypYsUguTOpb41cO0S0k2wdBEeqvtxaXQ==;EndpointSuffix=core.windows.net" />

Azure Storage Explorer生成的URL:

https://mystorage.blob.core.windows.net/profiles/169ae1c0-3307-401f-b45c-a50fa86cb1c6pic.png?sv=2016-05-31&ss=b&srt=sco&sp=r&se=2017-05-11T19:19:43Z&st=2017-05-11T09:19:43Z&spr=https&sig=ZpdhWPHZaUwECoorBwWidaresP50jannOx6ECUdd2Vw%3D

sv=2016-05-31
ss=b
srt=sco
sp=r
se=2017-05-11T19:19:43Z
st=2017-05-11T09:19:43Z
spr=https
sig=ZpdhWPHZaUwECoorBwWidaresP50jannOx6ECUdd2Vw%3D

Code生成的URL:

https://mystorage.blob.core.windows.net/profiles/169ae1c0-3307-401f-b45c-a50fa86cb1c6pic.png?sv=2016-05-31&sr=c&sig=JQgK68ycbhyq1xQ%2BQb6UDrUCcy3jwA8FEZVYununZVE%3D&st=2017-05-11T08%3A19%3A47Z&se=2017-05-11T12%3A19%3A47Z&sp=r

sv=2016-05-31
sr=c
sig=JQgK68ycbhyq1xQ%2BQb6UDrUCcy3jwA8FEZVYununZVE%3D
st=2017-05-11T08%3A19%3A47Z
se=2017-05-11T12%3A19%3A47Z
sp=r

新更新 2017年5月29日:
我决定改变我的方法并尝试这个:
    public static string GetBlobSasUri(string containerLocation, string blobName, string policyName = null)
    {
        string sasBlobToken;
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.
         ConnectionStrings["AzureStoreConnection"].ConnectionString);
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference(containerLocation);
        container.CreateIfNotExists();

        if (policyName == null)
        {
            SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy()
            {
                SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(120),
                SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-120),
                Permissions = SharedAccessBlobPermissions.Read

            };

            CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
            sasBlobToken = blob.GetSharedAccessSignature(adHocSAS);
            Console.WriteLine("SAS for blob (ad hoc): {0}", sasBlobToken);
            Console.WriteLine();

            return blob.Uri + HttpUtility.UrlEncode(sasBlobToken);
        }
        return null;
    }

错误已经改变,现在我遇到了以下错误:指定的资源不存在。

你是否正在尝试获取容器中的 Blob 列表? - Gaurav Mantri
不行。我正在尝试获取容器内一个 Blob 的 URL。 - ruizing
@GauravMantri 这也是正确的,这是我用于上传的。 - ruizing
您的连接字符串看起来也没问题。请问您正在使用哪个版本的SDK?我会尝试重现这个问题。 - Gaurav Mantri
@yonisha 没有工作。 - ruizing
显示剩余22条评论
2个回答

1
错误已经改变,现在我得到了以下错误:指定的资源不存在。 如果您编码了令牌,则最终URL如下。它不是一个格式良好的SAS Blob URL。
https://accountname.blob.core.windows.net/containername/blobname.jpg%3fsv%3d2016-05-31%26sr%3db%26sig%3dNGZzNbKvnR%252FRCnz1Dsk%252FJrSn8lVdqszyCF8MuLsdo0I%253D%26st%3d2017-05-31T05%253A32%253A00Z%26se%3d2017-05-31T09%253A32%253A00Z%26sp%3dr

这里有一种方法可以在不使用GetSharedAccessSignature方法的情况下生成SAS。请尝试并检查它是否能在你的端上工作。
private static string GetSharedAccessSignature(
       string accountName,
       string accountkey,
       string blobContainer,
       string blobName,
       DateTimeOffset sharedAccessStartTime,
       DateTimeOffset sharedAccessExpiryTime)
{
    var canonicalNameFormat = $"/blob/{accountName}/{blobContainer}/{blobName}";
    var st = sharedAccessStartTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
    var se = sharedAccessExpiryTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
    var sasVersion = "2016-05-31";

    string stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}", new object[]
    {
        "r",
        st,
        se,
        canonicalNameFormat,
        string.Empty,
        string.Empty,
        string.Empty,
        sasVersion,
        string.Empty,
        string.Empty,
        string.Empty,
        string.Empty,
        string.Empty
    });

    var sas = GetHash(stringToSign, accountkey);

    var credentials =
        $"?sv={sasVersion}&sr=b&sig={UrlEncoder.Default.Encode(sas)}&st={UrlEncoder.Default.Encode(st)}&se={UrlEncoder.Default.Encode(se)}&sp=r";

    string blobUri = $"https://{accountName}.blob.core.windows.net/{blobContainer}/{blobName}";
    return blobUri + credentials;
}

private static string GetHash(string stringToSign, string key)
{
    byte[] keyValue = Convert.FromBase64String(key);

    using (HMACSHA256 hmac = new HMACSHA256(keyValue))
    {
        return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
    }
}

你好。它也不起作用。<错误> <代码>BlobNotFound</代码> <消息> 指定的 Blob 不存在。RequestId:c7419ca6-0001-0002-75c2-de559b000000 时间:2017-06-06T12:44:04.7362370Z </消息> </错误>但是 Blob 存在。URL:https://.....blob.core.windows.net/profiles//1bcf382a-792b-4c53-b0a0-03e82773e15dpic.png?sv=2016-05-31&sr=b&sig=G9YlHjBHrvVI%2fzngwNzBWo%2fyVAnXtmN%2fMStQbcgaGMc%3d&st=2017-06-06T10%3a43%3a57Z&se=2017-06-06T14%3a43%3a57Z&sp=r - ruizing
BlobNotFound 表示在容器中找不到该 Blob。请在 Azure 存储资源管理器中打开您的存储帐户,并仔细检查该 Blob 是否存在于 Blob 容器中。 - Amor
是的,它存在。如果我不将容器设为私有,我就可以获取它们。 - ruizing
我在你的URL中发现了一个额外的'/'。 "/profiles//1bcf382a-792b"。请将其删除并重新测试。 - Amor
这不是问题 :( - ruizing
@ruizing 你找到问题了吗?我现在也遇到了类似的问题。我发现存储资源管理器生成的令牌在 sig 参数中有更长的值。 - Rasmus Christensen

0
你需要返回 'blob.Uri.AbsoluteUri + sasBlobToken'。
此外,建议将SharedAccessStartTime设置为(现在-5分钟),以克服不同机器之间的时钟差异。

我认为它们都不重要。我使用了原始帖子中的代码并获得了正确的URL。此外,我不认为时钟偏差是一个问题。如果是那样的话,错误消息会有所不同。 - Gaurav Mantri

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