当用于 Blob 存储的 Azure REST API 使用具有前缀或标记的查询字符串时获取 403
Posted
技术标签:
【中文标题】当用于 Blob 存储的 Azure REST API 使用具有前缀或标记的查询字符串时获取 403【英文标题】:Getting 403 when Azure REST API for blob storage with query strings having prefix or marker 【发布时间】:2020-05-29 08:57:40 【问题描述】:我正在尝试使用 Azure REST API 进行 Blob 存储,并且正在使用来自 https://github.com/Azure-Samples/storage-dotnet-rest-api-with-auth 的 AzureStorageAuthenticationHelper 来制作授权标头。
如果我这样做:
private static void DoItViaRest(string containerName, ILogger log)
try
string uri = string.Format("https://0.blob.core.windows.net/1?restype=container&comp=list", STORAGE_ACCOUNT_NAME, containerName);
byte[] requestPayload = null;
string xmlString = CallStorageRESTAPI(uri, requestPayload, log).Result;
catch (Exception e)
// handle exception
private static async Task<string> CallStorageRESTAPI(string uri, byte[] requestPayload, ILogger log)
string response = string.Empty;
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri) Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) )
DateTime now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R"));
httpRequestMessage.Headers.Add("x-ms-version", "2017-07-29");
httpRequestMessage.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY, now, httpRequestMessage);
using (HttpResponseMessage httpResponseMessage = await new HttpClient().SendAsync(httpRequestMessage))
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
response = await httpResponseMessage.Content.ReadAsStringAsync();
else
log.LogInformation(string.Format("REST returned 0", httpResponseMessage.StatusCode.ToString()));
return response;
然后由 AzureStorageAuthenticationHelper.GetAuthorizationHeader(STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY, now, httpRequestMessage) 创建的授权工作正常。
但是,如果我在 URI 的查询字符串中添加前缀或标记,那么我最终会得到 403。 带前缀的例子: https://0.blob.core.windows.net/1?restype=container&comp=list&prefix=2 https://0.blob.core.windows.net/1?restype=container&prefix=2&comp=list 带有标记的示例: https://0.blob.core.windows.net/1?restype=container&comp=list&marker=2 https://0.blob.core.windows.net/1?restype=container&marker=2&comp=list
上面的标记值是原始调用返回的 NextMarker。
我不知道出了什么问题或如何解决它。有什么建议吗?
【问题讨论】:
【参考方案1】:我相信您已经发现 Github 存储库中的代码存在问题。
基本上问题是由于以下代码行:
foreach (var item in values.AllKeys.OrderBy(k => k))
sb.Append('\n').Append(item).Append(':').Append(values[item]);
return sb.ToString().ToLower();
基本上这段代码所做的是获取所有查询字符串参数(名称和值)并以name:value
格式附加它们,然后最终将整个字符串转换为小写(这就是问题所在)。
根据documentation
,应该只将键名转换为小写而不是值部分。
要解决此问题,请使用以下代码:
/// <summary>
/// This part of the signature string represents the storage account
/// targeted by the request. Will also include any additional query parameters/values.
/// For ListContainers, this will return something like this:
/// /storageaccountname/\ncomp:list
/// </summary>
/// <param name="address">The URI of the storage service.</param>
/// <param name="accountName">The storage account name.</param>
/// <returns>String representing the canonicalized resource.</returns>
private static string GetCanonicalizedResource(Uri address, string storageAccountName)
// The absolute path is "/" because for we're getting a list of containers.
StringBuilder sb = new StringBuilder("/").Append(storageAccountName).Append(address.AbsolutePath);
// Address.Query is the resource, such as "?comp=list".
// This ends up with a NameValueCollection with 1 entry having key=comp, value=list.
// It will have more entries if you have more query parameters.
NameValueCollection values = HttpUtility.ParseQueryString(address.Query);
foreach (var item in values.AllKeys.OrderBy(k => k))
sb.Append('\n').Append(item.ToLower()).Append(':').Append(values[item]);
return sb.ToString();//We should not be converting entire thing to lower case.
但是,请注意,这仍然不是 100% 正确,因为它没有考虑上面屏幕截图中提到的第 9 点,但为了您的目的,它应该可以工作。
【讨论】:
解决了。非常感谢。我不知道我盯着输出看了多少小时,也没注意到标记值是小写的。以上是关于当用于 Blob 存储的 Azure REST API 使用具有前缀或标记的查询字符串时获取 403的主要内容,如果未能解决你的问题,请参考以下文章
REST Api 使用访问密钥到 Azure Blob 存储
使用 REST API 上传到 Azure Blob 存储时,Zip 档案损坏
请求令牌时如何在 Azure 存储 Blob 中为 REST 请求指定范围? [AZURE-BLOB][REST API]
仅从 Azure 存储 [Azure-Blob][REST] 中的 Blob 列表获取特定元数据
在 Azure 存储 [REST] [Azure Blob] 中对 PUT Blob 的 REST api 调用中的身份验证失败