Подпись общего доступа не работает в файлах Azure с подпапками
(Обновлено ниже с ответом) У меня была рабочая программа, которая хранит PDF-файлы в общей папке отчетов Azure Files ([domain].file.core.windows.net/reports). После сохранения файла я немедленно получаю подпись Shared Access для этого файла, объединяю его с физическим именем файла и сохраняю результат в записи транзакции отчета.
//create the storage location if it doesn't exist
var shareRoot = _blob.CreateCloudFileClient().GetShareReference("reports").GetRootDirectoryReference();
//get reference to azure file and copy the PDF report stream to it
CloudFile cloudFile = GetCloudFile("reports", storedFileName);
using (CloudFileStream strm = await cloudFile.OpenWriteAsync(stream.Length))
{
await stream.CopyToAsync(strm);
}
//get SAS using stored policy and create stored file name
string token = cloudFile.GetSharedAccessSignature(null, "myPolicy");
token = new Uri(cloudFile.StorageUri.PrimaryUri.ToString() + token).ToString();
// function to centralize calls for files
private CloudFile GetCloudFile(string fileShare, string fileName)
{
// Parse the connection string and get a reference to storage file
//See UPDATE below: ***THIS WAS THE PROBLEM*****
return _blob.CreateCloudFileClient().GetShareReference(fileShare).GetRootDirectoryReference().GetFileReference(fileName);
}
Пример сохраненной строки доступа к файлу из старого кода: https: // [домен].file.core.windows.net/reports/[имя файла].pdf? Sv = 2018-03-28 & sr = f & si = myPolicy & sig = Wd1BkHPRTPHDiezA% 2FWe4CD4mOJIyILxDUXbyUhHH % 3D
В любой момент я мог вставить этот URL в браузер и вызвать PDF.
Все работало хорошо, пока в каталоге "отчетов" не было слишком много отчетов для прокрутки, поэтому я изменил программу для создания подпапок в каталоге "отчеты" на основе месяца (например, "201902"). Физическое местоположение файла теперь [домен].file.core.windows.net/reports/201902. Я изменил код, чтобы добавить подпапку и сохранить в ней файл:
//create the storage location if it doesn't exist -- same as before
var shareRoot = _blob.CreateCloudFileClient().GetShareReference("reports").GetRootDirectoryReference();
//create new subfolder if needed
await shareRoot.GetDirectoryReference("201902").CreateIfNotExistsAsync();
//get reference to azure file in subfolder and copy the PDF report stream to it
CloudFile cloudFile = GetCloudFile("reports/201902", storedFileName);
С этого момента строка токена больше не может обращаться к PDF.
Пример сохраненной строки доступа к файлу из нового кода: https: // [домен].file.core.windows.net/reports/201902/[имя файла].pdf? Sv = 2018-03-28 & sr = f & si = myPolicy & sig = YZ64hSk5IKQOs % 2BhgACfBlQk% 2F6r8OqiA7D8DBv% 2F3G% 2FyA% 3D
Когда я вставляю эту строку в адресную строку, получается
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:e51d0e3c-e01a-003e-27bf-c49bf8000000 Time:2019-02-14T23:46:20.4325820Z</Message>
<AuthenticationErrorDetail>Signature did not match. String to sign used was /file/[domain]/reports/201902/[filename].pdf myPolicy 2018-03-28 </AuthenticationErrorDetail>
</Error>
Никаких других изменений не было сделано - ключ доступа такой же и т. Д. Если я перехожу к файлу на портале Azure, он действительно хранится в reports / 201902 с указанным мной именем файла. Я могу загрузить его с портала без проблем (но портал генерирует свой собственный токен SAS, так что это не помогает).
Думая, что это может быть связано с хранимой политикой (myPolicy), я сгенерировал новую и попробовал, но ничего не изменилось. Политика хранится в корне общего ресурса (отчеты), а не в подпапке (reports/201902), поскольку нет способа указать политику на уровне подпапок.
Если у кого-то есть какие-либо предложения, я буду признателен.
1 ответ
ОБНОВЛЕНИЕ С ОТВЕТОМ
Как правильно предположил Гаурав Мантри, проблема была в методе GetCloudFile, куда я даже не смотрел. При создании файла он получал ссылку на корневой каталог "отчеты" вместо подпапки "201902". Путем явного указания "reports/201902" в имени файла, которое нужно сохранить, Azure помещал файл в нужное место, но SAS записывался для корневого общего ресурса "reports", а не для подпапки "201902". Таким образом, никогда не будет никакого способа вызвать файл, потому что физический URI был правильным, но безопасность никогда не будет соответствовать.
Новый код показан ниже. Спасибо Гаураву за правильный вопрос.
Новый код, который работает:
//UPDATED: moved folder creation to GetCloudFile method
//UPDATED: get reference to azure file and copy the PDF report stream to it
CloudFile cloudFile = await GetCloudFile(REPORT_SHARE, fPath, storedFileName);
using (CloudFileStream strm = await cloudFile.OpenWriteAsync(stream.Length))
{
await stream.CopyToAsync(strm);
}
//get SAS using stored policy and create stored file name
string token = cloudFile.GetSharedAccessSignature(null, "myPolicy");
token = new Uri(cloudFile.StorageUri.PrimaryUri.ToString() + token).ToString();
// UPDATED: method to get the cloud file to store uploads and reports
private async Task<CloudFile> GetCloudFile(string shareRoot, string shareFolder, string fileName)
{
//create the subpath if it doesn't exist
var sRoot = _blob.CreateCloudFileClient().GetShareReference(shareRoot).GetRootDirectoryReference();
await sRoot.GetDirectoryReference(shareFolder).CreateIfNotExistsAsync();
//create and return the file reference
return sRoot.GetDirectoryReference(shareFolder).GetFileReference(fileName);
}