指向 Azure 存储资源的链接仅在第一次有效
Links to Azure Storage Resource Only Work First Time
我们正在使用 SAS 密钥从我们的 Azure 服务器访问文件。使用 ASP.NET 控制器检索 link 并使用 HTML 元素显示。
我们第一次请求 link 时,图像完美显示。第二次请求图像(例如页面刷新)时,它们没有显示 - 控制台显示 403 找不到图像文件。如果我们将 link 从 HTML 元素复制到新的浏览器选项卡中,则会显示图像。
有人遇到过这个问题吗?
谢谢。
控制器
// GET: /<controller>/edit
public async Task<IActionResult> Edit(int id)
{
Checklist checklist = await AM.Checklist.FindAsync(id);
if (checklist == null)
{
return StatusCode(404);
}
ChecklistViewModel cVM = new ChecklistViewModel(checklist);
cVM.productPartNum = (await AM.Product.FindAsync(checklist.productNum)).partId;
cVM.checklistTypesDropdown = await cVM.GetChecklistOptions(AM);
List<Field> fields = await AM.Field.Where(x => x.checklistId == checklist.id).OrderBy(x=>x.section).ThenBy(x=>x.order).ToListAsync();
//connect to the file storate account
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create a CloudFileClient object for credentialed access to File storage.
CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
// Get a reference to the file share
CloudFileShare share = fileClient.GetShareReference("newfileshare");
string policyName = "sampleSharePolicy" + DateTime.UtcNow.Ticks;
CloudFileDirectory rootDir = null;
CloudFileDirectory fileDir = null;
// Ensure that the share exists.
if (share.Exists())
{
// Create a new shared access policy and define its constraints.
SharedAccessFilePolicy sharedPolicy = new SharedAccessFilePolicy()
{
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(8),
Permissions = SharedAccessFilePermissions.Read | SharedAccessFilePermissions.Write
};
// Get existing permissions for the share.
FileSharePermissions permissions = await share.GetPermissionsAsync();
//Check length of SharedAccessPolicies
if (permissions.SharedAccessPolicies.Count >= 5)
{
permissions.SharedAccessPolicies.Remove(permissions.SharedAccessPolicies.Keys.First());
}
// Add the shared access policy to the share's policies. Note that each policy must have a unique name.
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
await share.SetPermissionsAsync(permissions);
// Generate a SAS for a file in the share and associate this access policy with it.
rootDir = share.GetRootDirectoryReference();
}
cVM.changeHappened = new List<bool>();
cVM.Fields = new List<FieldViewModel>();
int i = 0;
foreach(Field f in fields)
{
FieldViewModel newFVM = new FieldViewModel(f);
cVM.changeHappened.Add(false);
if (f.attachmentReq && f.attachmentData != null)
{
//changeHappened will keep track of what images have been changed in order to avoid resubmitting same images
cVM.changeHappened.Add(false);
if (f.attachmentType.Contains("image"))
{
fileDir = rootDir.GetDirectoryReference("Images");
}
else
{
fileDir = rootDir.GetDirectoryReference("files");
}
CloudFile file = fileDir.GetFileReference(f.attachmentData);
string sasToken = file.GetSharedAccessSignature(null, policyName);
string tick = $"&{ DateTimeOffset.UtcNow.Ticks}";
Uri fileSasUri = new Uri(file.StorageUri.PrimaryUri.ToString() + sasToken + tick);
newFVM.link = fileSasUri.AbsoluteUri;
//// Create a new CloudFile object from the SAS, and write some text to the file.
//CloudFile fileSas = new CloudFile(fileSasUri);
//fileSas.UploadText("This write operation is authenticated via SAS.");
//Console.WriteLine(fileSas.DownloadText());
}
if (newFVM.textReq)
{
newFVM.fieldDropdownOptions = await newFVM.getDropdownOptions(AM);
}
cVM.Fields.Add(newFVM);
}
return View(cVM);
}
Div 显示图像
<div class="col-sm-5">
@if (Model.Fields[i].attachmentData != null)
{
@if (Model.Fields[i].attachmentType.Contains("image/"))
{
<img src="@Model.Fields[i].link" id="image_@i" height="50" width="50" align="middle"/>
<a hidden="hidden" id="link_@i"></a>
}
else
{
<img hidden="hidden" id="image_@i" height="50" width="50" align="middle"/>
<a id="link_@i">@Model.Fields[i].attachmentData</a>
}
}
else
{
<img hidden="hidden" id="image_@i" height="50" width="50" align="middle"/>
<a hidden="hidden" id="link_@i"></a>
}
</div>
根据你的描述和代码,我已经重现了问题。
我猜你遇到 403 错误的原因是你的 MVC 代码在文件存储已经设置并启用权限的 SharedAccessPolicies 之前向文件存储发送请求。
所以它会 return 403 forbidden error 说你的 SAS 令牌没用。
另外,我不建议你每次都添加SharedAccessPolicies,因为如果6个人同时访问你的网站,第一个人的SharedAccessPolicies可能会被删除。所以第一个人获取不到文件图片
我建议你可以只使用一个 SharedAccessPolicies。
您可以每次重新设置 SharedAccessFilePolicy 的 SharedAccessExpiryTime。
更多细节,您可以参考下面的代码示例:
//connect to the file storate account
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(" ");
// Create a CloudFileClient object for credentialed access to File storage.
CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
// Get a reference to the file share
CloudFileShare share = fileClient.GetShareReference("brandofirstsharetest");
string policyName = "sampleSharePolicy" + DateTime.UtcNow.Ticks;
CloudFileDirectory rootDir = null;
CloudFileDirectory fileDir = null;
// Ensure that the share exists.
if (share.Exists())
{
// Get existing permissions for the share.
FileSharePermissions permissions = await share.GetPermissionsAsync();
//if the SharedAccessPolicies is exists just get the SharedAccessPolicies
if (permissions.SharedAccessPolicies.Count > 0)
{
policyName = permissions.SharedAccessPolicies.First().Key;
SharedAccessFilePolicy sharedPolicy = permissions.SharedAccessPolicies.First().Value;
sharedPolicy.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(8);
await share.SetPermissionsAsync(permissions);
}
else
{
// Create a new shared access policy and define its constraints.
SharedAccessFilePolicy sharedPolicy = new SharedAccessFilePolicy()
{
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-15),
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(8),
Permissions = SharedAccessFilePermissions.Read | SharedAccessFilePermissions.Write
};
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
await share.SetPermissionsAsync(permissions);
}
// Add the shared access policy to the share's policies. Note that each policy must have a unique name.
// Generate a SAS for a file in the share and associate this access policy with it.
rootDir = share.GetRootDirectoryReference();
}
CloudFile file = rootDir.GetFileReference("Penjs.png");
string sasToken = file.GetSharedAccessSignature(null, policyName);
string tick = $"&{ DateTimeOffset.UtcNow.Ticks}";
Uri fileSasUri = new Uri(file.StorageUri.PrimaryUri.ToString() + sasToken + tick);
我们正在使用 SAS 密钥从我们的 Azure 服务器访问文件。使用 ASP.NET 控制器检索 link 并使用 HTML 元素显示。
我们第一次请求 link 时,图像完美显示。第二次请求图像(例如页面刷新)时,它们没有显示 - 控制台显示 403 找不到图像文件。如果我们将 link 从 HTML 元素复制到新的浏览器选项卡中,则会显示图像。
有人遇到过这个问题吗?
谢谢。
控制器
// GET: /<controller>/edit
public async Task<IActionResult> Edit(int id)
{
Checklist checklist = await AM.Checklist.FindAsync(id);
if (checklist == null)
{
return StatusCode(404);
}
ChecklistViewModel cVM = new ChecklistViewModel(checklist);
cVM.productPartNum = (await AM.Product.FindAsync(checklist.productNum)).partId;
cVM.checklistTypesDropdown = await cVM.GetChecklistOptions(AM);
List<Field> fields = await AM.Field.Where(x => x.checklistId == checklist.id).OrderBy(x=>x.section).ThenBy(x=>x.order).ToListAsync();
//connect to the file storate account
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create a CloudFileClient object for credentialed access to File storage.
CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
// Get a reference to the file share
CloudFileShare share = fileClient.GetShareReference("newfileshare");
string policyName = "sampleSharePolicy" + DateTime.UtcNow.Ticks;
CloudFileDirectory rootDir = null;
CloudFileDirectory fileDir = null;
// Ensure that the share exists.
if (share.Exists())
{
// Create a new shared access policy and define its constraints.
SharedAccessFilePolicy sharedPolicy = new SharedAccessFilePolicy()
{
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(8),
Permissions = SharedAccessFilePermissions.Read | SharedAccessFilePermissions.Write
};
// Get existing permissions for the share.
FileSharePermissions permissions = await share.GetPermissionsAsync();
//Check length of SharedAccessPolicies
if (permissions.SharedAccessPolicies.Count >= 5)
{
permissions.SharedAccessPolicies.Remove(permissions.SharedAccessPolicies.Keys.First());
}
// Add the shared access policy to the share's policies. Note that each policy must have a unique name.
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
await share.SetPermissionsAsync(permissions);
// Generate a SAS for a file in the share and associate this access policy with it.
rootDir = share.GetRootDirectoryReference();
}
cVM.changeHappened = new List<bool>();
cVM.Fields = new List<FieldViewModel>();
int i = 0;
foreach(Field f in fields)
{
FieldViewModel newFVM = new FieldViewModel(f);
cVM.changeHappened.Add(false);
if (f.attachmentReq && f.attachmentData != null)
{
//changeHappened will keep track of what images have been changed in order to avoid resubmitting same images
cVM.changeHappened.Add(false);
if (f.attachmentType.Contains("image"))
{
fileDir = rootDir.GetDirectoryReference("Images");
}
else
{
fileDir = rootDir.GetDirectoryReference("files");
}
CloudFile file = fileDir.GetFileReference(f.attachmentData);
string sasToken = file.GetSharedAccessSignature(null, policyName);
string tick = $"&{ DateTimeOffset.UtcNow.Ticks}";
Uri fileSasUri = new Uri(file.StorageUri.PrimaryUri.ToString() + sasToken + tick);
newFVM.link = fileSasUri.AbsoluteUri;
//// Create a new CloudFile object from the SAS, and write some text to the file.
//CloudFile fileSas = new CloudFile(fileSasUri);
//fileSas.UploadText("This write operation is authenticated via SAS.");
//Console.WriteLine(fileSas.DownloadText());
}
if (newFVM.textReq)
{
newFVM.fieldDropdownOptions = await newFVM.getDropdownOptions(AM);
}
cVM.Fields.Add(newFVM);
}
return View(cVM);
}
Div 显示图像
<div class="col-sm-5">
@if (Model.Fields[i].attachmentData != null)
{
@if (Model.Fields[i].attachmentType.Contains("image/"))
{
<img src="@Model.Fields[i].link" id="image_@i" height="50" width="50" align="middle"/>
<a hidden="hidden" id="link_@i"></a>
}
else
{
<img hidden="hidden" id="image_@i" height="50" width="50" align="middle"/>
<a id="link_@i">@Model.Fields[i].attachmentData</a>
}
}
else
{
<img hidden="hidden" id="image_@i" height="50" width="50" align="middle"/>
<a hidden="hidden" id="link_@i"></a>
}
</div>
根据你的描述和代码,我已经重现了问题。
我猜你遇到 403 错误的原因是你的 MVC 代码在文件存储已经设置并启用权限的 SharedAccessPolicies 之前向文件存储发送请求。
所以它会 return 403 forbidden error 说你的 SAS 令牌没用。
另外,我不建议你每次都添加SharedAccessPolicies,因为如果6个人同时访问你的网站,第一个人的SharedAccessPolicies可能会被删除。所以第一个人获取不到文件图片
我建议你可以只使用一个 SharedAccessPolicies。
您可以每次重新设置 SharedAccessFilePolicy 的 SharedAccessExpiryTime。
更多细节,您可以参考下面的代码示例:
//connect to the file storate account
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(" ");
// Create a CloudFileClient object for credentialed access to File storage.
CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
// Get a reference to the file share
CloudFileShare share = fileClient.GetShareReference("brandofirstsharetest");
string policyName = "sampleSharePolicy" + DateTime.UtcNow.Ticks;
CloudFileDirectory rootDir = null;
CloudFileDirectory fileDir = null;
// Ensure that the share exists.
if (share.Exists())
{
// Get existing permissions for the share.
FileSharePermissions permissions = await share.GetPermissionsAsync();
//if the SharedAccessPolicies is exists just get the SharedAccessPolicies
if (permissions.SharedAccessPolicies.Count > 0)
{
policyName = permissions.SharedAccessPolicies.First().Key;
SharedAccessFilePolicy sharedPolicy = permissions.SharedAccessPolicies.First().Value;
sharedPolicy.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(8);
await share.SetPermissionsAsync(permissions);
}
else
{
// Create a new shared access policy and define its constraints.
SharedAccessFilePolicy sharedPolicy = new SharedAccessFilePolicy()
{
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-15),
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(8),
Permissions = SharedAccessFilePermissions.Read | SharedAccessFilePermissions.Write
};
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
await share.SetPermissionsAsync(permissions);
}
// Add the shared access policy to the share's policies. Note that each policy must have a unique name.
// Generate a SAS for a file in the share and associate this access policy with it.
rootDir = share.GetRootDirectoryReference();
}
CloudFile file = rootDir.GetFileReference("Penjs.png");
string sasToken = file.GetSharedAccessSignature(null, policyName);
string tick = $"&{ DateTimeOffset.UtcNow.Ticks}";
Uri fileSasUri = new Uri(file.StorageUri.PrimaryUri.ToString() + sasToken + tick);