I have an azure function that generates a sas key that I later use to upload files to my blob. Here is how I generate the sas key :
CloudBlobContainer container = blobClient.GetContainerReference("sasimagecontainer");
container.CreateIfNotExists();
static string GetContainerSasUri(CloudBlobContainer container)
{
//Set the expiry time and permissions for the container.
//In this case no start time is specified, so the shared access signature becomes valid immediately.
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessStartTime = DateTimeOffset.UtcNow.AddMinutes(-5);
sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddMinutes(25);
sasConstraints.Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Add | SharedAccessBlobPermissions.Create;
//Generate the shared access signature on the container, setting the constraints directly on the signature.
string sasContainerToken = container.GetSharedAccessSignature(sasConstraints);
//Return the URI string for the container, including the SAS token.
return container.Uri + sasContainerToken + "&comp=list&restype=container";
}
And then I can call
GetContainerSasUri(container));
to get the sas key. But when I use the following code to call it :
CloudBlockBlob blob = new CloudBlockBlob(thesaskey);
using (var fileStream = File.OpenRead(file))
{
await blob.UploadFromStreamAsync(fileStream);
}
I keep getting 403 errors. That's all I'm getting from debugging in VS 2017, I'm not sure how can I acquire more information about this problem.
I already looked into most similar threads on SO regarding similar issues and applied possible fixes, like for example the "&comp=list&restype=container" parameter at the end.
// I tried adding SharedAccessBlobPermissions.List to permissions, that didn't work.
// I added literally all the permissions (except None, of course) to check if that might change something - it doesn't. The goal is still to only have permissions to upload.
I was able to reproduce the error and this is how I fixed it:
You need to pass the SAS to a CloudBlobContainer
instead of a CloudBlockBlob
. Then use the container to retrieve a blob reference (you may want to use the filename property of your file):
var container = new CloudBlobContainer(thesaskey);
var blob = container.GetBlockBlobReference("<yourFileName>");
await blob.UploadFromFileAsync(@"YOURPATH")
Notice that there is a convenience method UploadFromFileAsync
that you can use
Here is the console application that I used to test it:
class Program
{
static void Main(string[] args)
{
var connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
"<AccountName>",
"<AccountKey>");
var storageAccount = CloudStorageAccount.Parse(connectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("sasimagecontainer");
container.CreateIfNotExistsAsync().GetAwaiter().GetResult();
var sasUri = GetContainerSasUri(container);
var container2 = new CloudBlobContainer(new Uri(sasUri));
var blob2 = container2.GetBlockBlobReference("blobCreatedViaSAS.txt");
blob2.UploadFromFileAsync(@"D:\test.txt").GetAwaiter().GetResult();
}
private static string GetContainerSasUri(CloudBlobContainer container)
{
//Set the expiry time and permissions for the container.
//In this case no start time is specified, so the shared access signature becomes valid immediately.
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24);
sasConstraints.Permissions = SharedAccessBlobPermissions.List | SharedAccessBlobPermissions.Write |
SharedAccessBlobPermissions.Create |
SharedAccessBlobPermissions.Add | SharedAccessBlobPermissions.Read;
//Generate the shared access signature on the container, setting the constraints directly on the signature.
var sasContainerToken = container.GetSharedAccessSignature(sasConstraints);
//Return the URI string for the container, including the SAS token.
return container.Uri + sasContainerToken;
}
}