Carson
Carson

Reputation: 894

Using Azure.Storage.Blobs to generate SAS expiring tokens with .NET Core 3.1

Having some trouble with this one. I'm getting an SAS token generated after following the examples in Microsoft's documentation, but am having issues with the SAS token not being authenticated.

string sastoken = "";
            BlobServiceClient blobServiceClient = new BlobServiceClient("DefaultEndpointsProtocol=https;AccountName=accountname;AccountKey=accountkey;EndpointSuffix=core.windows.net");
            string containerName = containername;
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
            BlobSasBuilder sasBuilder = new BlobSasBuilder()
            {
                ExpiresOn = DateTime.UtcNow + (new TimeSpan(24, 0, 0)),
                BlobContainerName = containerName,
                BlobName = imageData.filename,
                Resource = "b"
            };

            sasBuilder.SetPermissions(BlobSasPermissions.Read);
            sastoken = sasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(containername, credentialkey)).ToString();

            UriBuilder fulluri = new UriBuilder()
            {
                Scheme = "https",
                Host = string.Format("{0}.blob.core.windows.net", containername),
                Path = string.Format("{0}/{1}", "blobtest", "file.bmp"),
                Query = sastoken
            };

            imageData.url = fulluri.Uri.ToString();

imageData.url returns as: https://accountname.blob.core.windows.net/containername/file.bmp?sv=2019-07-07&se=2020-07-10T14%3A54%3A43Z&sr=b&sp=r&sig=UXvC7SAXqQtsVgfXj6L%2BOIinTMhQj%2F3NH95v%2FLRvM8g%3D

I get an authentication error, but the entire point of SAS tokens is to provide that authentication. I'm sure that I'm missing something here, but haven't found anywhere that I'm making a mistake. Most of the information I find is related to the Microsoft.Azure.Storage package rather than the Azure.Storage.Blob namespace. Any help or advice would be welcome. Thanks!

Upvotes: 5

Views: 6970

Answers (3)

Danthar
Danthar

Reputation: 1075

Since a year or 2 there is official migration guidance docs available. These also expose the existence of a convenience method for generating a sas token url.

// Create a BlobClient with a shared key credential
BlobClient blobClient = new BlobClient(blobUri, sharedKeyCredential);

Uri sasUri;
// Ensure our client has the credentials required to generate a SAS
if (blobClient.CanGenerateSasUri)
{
    // Create full, self-authenticating URI to the resource from the BlobClient
    sasUri = blobClient.GenerateSasUri(BlobSasPermissions.Read, DateTimeOffset.UtcNow.AddHours(1));

    // Use newly made as SAS URI to download the blob
    await new BlobClient(sasUri).DownloadToAsync(new MemoryStream());
}

This example and more can be found here:

https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/AzureStorageNetMigrationV12.md#generate-a-sas

Upvotes: 0

galdin
galdin

Reputation: 14034

I use something like this, using the Microsoft.WindowsAzure.Storage nuget package:

private Uri GetSasForBlob(CloudBlob blob, DateTime expiry, SharedAccessBlobPermissions permissions = SharedAccessBlobPermissions.None)
{
    var offset = TimeSpan.FromMinutes(10);
    var policy = new SharedAccessBlobPolicy
    {
        SharedAccessStartTime = DateTime.UtcNow.Subtract(offset),
        SharedAccessExpiryTime = expiry.Add(offset),
                Permissions = permissions
    };
#pragma warning disable CA5377 // Use Container Level Access Policy
    var sas = blob.GetSharedAccessSignature(policy);
#pragma warning restore CA5377 // Use Container Level Access Policy
    return new Uri($"{blob.Uri}{sas}");
}

UPDATE using Azure.Storage.Blobs:

// Read these from config:
// var accountName = "accountname";
// var accountKey = "xxxxxxx";
// var blobServiceEndpoint = $"https://{accountName}.blob.core.windows.net";


private Uri GetSasForBlob(string blobname, string containerName, DateTime expiry, BlobAccountSasPermissions permissions = BlobAccountSasPermissions.Read)
{
    var offset = TimeSpan.FromMinutes(10);

    var credential = new StorageSharedKeyCredential(accountName, accountKey);
    var sas = new BlobSasBuilder
    {
        BlobName = blobname,
        BlobContainerName = containerName,
        StartsOn = DateTime.UtcNow.Subtract(offset),
        ExpiresOn = expiry.Add(offset)
    };
    sas.SetPermissions(permissions);

    UriBuilder sasUri = new UriBuilder($"{blobServiceEndpoint}/{containerName}/{blobname}");
    sasUri.Query = sas.ToSasQueryParameters(credential).ToString();

    return sasUri.Uri;
}

Reference: https://github.com/Azure/azure-sdk-for-net/blob/42839e7dea6be316024f168ecd08f3134bc57a47/sdk/storage/Azure.Storage.Blobs/samples/Sample02_Auth.cs#L137

Upvotes: 4

Artak
Artak

Reputation: 2887

It looks like your generated SAS token and URL are using different values for account name, container name and blob name. Consider updating the URL generation code to use the same values.

UriBuilder fulluri = new UriBuilder()
{
  Scheme = "https",
  Host = string.Format("{0}.blob.core.windows.net", accountname),
  Path = string.Format("{0}/{1}", containerName, imageData.fileName),
  Query = sastoken
};

Hope this helps.

Upvotes: 1

Related Questions