Azure, доступ запрещен для подписи общего доступа для хранилища 2.0

У меня проблемы с получением подписей общего доступа для работы с Storage 2.0.

Я использую код:

if (blob.Exists())
{
    var expires = DateTime.UtcNow.AddMinutes(30);
    var sas = blob.GetSharedAccessSignature(new Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPolicy
    {
        Permissions = Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPermissions.Read,
        SharedAccessExpiryTime = expires
    });
    url = string.Concat(blob.Uri.AbsoluteUri, sas);
}
return url;

Но если я отлаживаю сеанс и вставляю URL в браузер, я получаю сообщение об ошибке:

<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:c1a1dd2b-bf4a-4a6b-bab2-ab1cb9363d27 Time:2012-11-19T14:41:51.1254531Z
  </Message>
  <AuthenticationErrorDetail>
Signature did not match. String to sign used was r 2012-11-19T15:11:36Z /container/path/1356/pic.jpg 2012-02-12
  </AuthenticationErrorDetail>
</Error>

Кто-нибудь может помочь?

ОБНОВЛЕНИЕ: итоговый URL выглядит следующим образом: https://storageaccountname.blob.core.windows.net/container/path/1356/pic.jpg?sv=2012-02-12&se=2012-11-19T19%3A25%3A32Z&sr=b&sp=r&sig=s6QIdwAGY4xC8fs4L9pK8hAGIY%2F8x58aqBcFbejYPdM%3D

2 ответа

Решение

Я получаю ту же ошибку. Этот код работал до того, как я обновился до 2.0:

var sharedAccessPolicy = new SharedAccessBlobPolicy
{
  SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-10),
  SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30),
  Permissions = SharedAccessBlobPermissions.Read
};
var sharedAccessSignature = _blockblob.GetSharedAccessSignature(sharedAccessPolicy);
return _blockblob.Uri.AbsoluteUri + sharedAccessSignature;

Я получаю URI:

http://127.0.0.1:10000/devstoreaccount1/original/c04d2a1c-980b-42c5-b76e-b71185f027b6.jpg?sv=2012-02-12&st=2012-11-20T08%3A30%3A24Z&se=2012-11-20T09%3A10%3A24Z&sr=b&sp=r&sig=9%2BVg6mSGqyrfr5rPlNJ6GSv%2BHN3J9k%2FWFRLYmx3xCvQ%3D

ОБНОВЛЕНИЕ, РЕШЕНО:

В моем коде выше у меня есть _blockBlob. Это было установлено в конструкторе с

var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
CloudBlockBlob _blockblob = container.GetBlockBlobReference(fileName);

Изменение последней строки (как предложено clausndk) на

ICloudBlob _test = container.GetBlobReferenceFromServer(fileName);

решает проблему, так как вызов GetSharedAccessSignature в _test приводит к другой (действительной) подписи.

Просматривая исходный код хранилища Azure и используя отладчик в моем приложении, я нашел причину проблемы. В моем коде у меня есть containerName с косой чертой (оригинал /). Это не проблема, за исключением случаев, когда речь идет о GetSharedAccessSignature. Здесь дополнительная косая черта портит canonicalName (одна косая черта добавляется в код, дающий двойные косые черты), и это делает подпись недействительной. Причина, по которой GetBlobReferenceFromServer работает, заключается в том, что он запрашивает у серверов (через REST API) большой двоичный объект, а в результате CloudBlockBlob удаляет косую черту.

В моем коде я удалил косую черту, но решение Сандрино Ди Маттиа использовать.Trim('/') в имени контейнера также работает. Я думаю, что это предпочтительнее, чем использование GetBlobReferenceFromServer, так как это вызовет дополнительный серверный вызов.

Надеемся, что реализация GetCanonicalName в CloudBlockBlobBase будет изменена для обработки завершающих слешей в будущем (для этого я создал проблему на GitHub), но пока этот "обходной путь" работает.

Не могли бы вы попробовать следующий код?

var pathToMyBlob = "/path/1356/pic.jpg";
var blob = container.GetBlockBlobReference(pathToMyBlob.TrimStart('/'));

var expires = DateTime.UtcNow.AddMinutes(30);
var sas = blob.GetSharedAccessSignature(new Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPolicy
{
    Permissions = Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPermissions.Read,
    SharedAccessExpiryTime = expires
});

Посмотрите на вторую строку, особенно на звонок в TrimStart. Я смог воспроизвести проблему при попытке получить ссылку на BLOB-файл файла, путь к которому начинался с косой черты. После удаления косой черты проблема была исправлена. Так:

  • /path/1356/pic.jpg > Не работает
  • путь / 1356 / pic.jpg> Работы
Другие вопросы по тегам