(下面用答案更新) 我有一个工作程序,将PDF存储在Azure文件的“报告”共享中([domain] .file.core.windows.net / reports)。存储文件后,我立即获得该文件的共享访问签名,将其连接到物理文件名上,并将结果存储在报告事务记录中。
//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://[domain].file.core.windows.net/reports/[filename].pdf?sv=2018-03-28&sr=f&si=myPolicy&sig=Wd1BkHPRTPHDiezA%2FWe4CD4mOJIyILxDUXxrxjH1byU%3D
任何时候我都可以将该URL粘贴到浏览器中并调用PDF。
一切正常,直到我无法在'reports'目录中滚动太多报告为止,因此我修改了程序以根据月份(例如'201902')在'reports'目录中创建子文件夹。物理文件位置现在为[domain] .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://[domain].file.core.windows.net/reports/201902/[filename].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 Portal中的文件,则该文件确实以我指定的文件名存储在report / 201902中。我可以毫无问题地从门户网站下载它(但是门户网站会生成自己的SAS令牌,因此无济于事)。
考虑到它可能与存储策略(myPolicy)有关,我生成了一个新策略并进行了尝试,但没有任何变化。该策略存储在共享根目录(报告)而非子文件夹(reports / 201902)中,因为无法在子文件夹级别指定策略。
如果有人有任何建议,我将不胜感激。
答案 0 :(得分:0)
用答案更新
正如Gaurav Mantri正确推测的那样,问题出在我甚至没有看过的GetCloudFile方法中。创建文件时,它得到的是对根目录“ reports”的引用,而不是对子文件夹“ 201902”的引用。通过在要存储的文件名中明确指定“ reports / 201902”,Azure将文件放置在正确的位置,但是SAS是针对根“ reports”共享而不是针对“ 201902”子文件夹编写的。因此,由于物理URI正确,但是安全性永远不匹配,因此永远不会有任何方法来调用该文件。
新代码如下所示。感谢Gaurav提出了正确的问题。
有效的新代码:
//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);
}