title | description | services | author | ms.service | ms.topic | ms.devlang | ms.date | ms.author | ms.component |
---|---|---|---|---|---|---|---|---|---|
Create and use a shared access signature (SAS) with Azure Blob storage | Microsoft Docs |
This tutorial shows you how to create shared access signatures for use with Blob storage, and how to consume them in your client applications. |
storage |
tamram |
storage |
article |
dotnet |
05/15/2017 |
tamram |
blobs |
Part 1 of this tutorial explored shared access signatures (SAS) and explained best practices for using them. Part 2 shows you how to generate and then use shared access signatures with Blob storage. The examples are written in C# and use the Azure Storage Client Library for .NET. The examples in this tutorial:
- Generate a shared access signature on a container
- Generate a shared access signature on a blob
- Create a stored access policy to manage signatures on a container's resources
- Test the shared access signatures in a client application
In this tutorial, we create two console applications that demonstrate creating and using shared access signatures for containers and blobs:
Application 1: The management application. Generates a shared access signature for a container and a blob. Includes the storage account access key in source code.
Application 2: The client application. Accesses container and blob resources using the shared access signatures created with the first application. Uses only the shared access signatures to access container and blob resources--it does not include the storage account access key.
First, ensure that you have the Azure Storage Client Library for .NET installed. You can install the NuGet package containing the most up-to-date assemblies for the client library. This is the recommended method for ensuring that you have the most recent fixes. You can also download the client library as part of the most recent version of the Azure SDK for .NET.
In Visual Studio, create a new Windows console application and name it GenerateSharedAccessSignatures. Add references to Microsoft.WindowsAzure.ConfigurationManager and WindowsAzure.Storage by using one of the following approaches:
- Use the NuGet package manager in Visual Studio. Select Project > Manage NuGet Packages, search online for each package (Microsoft.WindowsAzure.ConfigurationManager and WindowsAzure.Storage) and install them.
- Alternatively, locate these assemblies in your installation of the Azure SDK and add references to them:
- Microsoft.WindowsAzure.Configuration.dll
- Microsoft.WindowsAzure.Storage.dll
At the top of the Program.cs file, add the following using directives:
using System.IO;
using Microsoft.Azure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
Edit the app.config file so that it contains a configuration setting with a connection string that points to your storage account. Your app.config file should look similar to this one:
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<appSettings>
<add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey"/>
</appSettings>
</configuration>
To begin with, we add a method to generate a shared access signature on a new container. In this case, the signature is not associated with a stored access policy, so it carries on the URI the information indicating its expiry time and the permissions it grants.
First, add code to the Main() method to authorize access to your storage account and create a new container:
static void Main(string[] args)
{
//Parse the connection string and return a reference to the storage account.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
//Create the blob client object.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
//Get a reference to a container to use for the sample code, and create it if it does not exist.
CloudBlobContainer container = blobClient.GetContainerReference("sascontainer");
container.CreateIfNotExists();
//Insert calls to the methods created below here...
//Require user input before closing the console window.
Console.ReadLine();
}
Next, add a method that generates the shared access signature for the container and returns the signature URI:
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;
//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;
}
Add the following lines at the bottom of the Main() method, before the call to Console.ReadLine(), to call GetContainerSasUri() and write the signature URI to the console window:
//Generate a SAS URI for the container, without a stored access policy.
Console.WriteLine("Container SAS URI: " + GetContainerSasUri(container));
Console.WriteLine();
Compile and run to output the shared access signature URI for the new container. The URI will be similar to the following:
https://storageaccount.blob.core.windows.net/sascontainer?sv=2012-02-12&se=2013-04-13T00%3A12%3A08Z&sr=c&sp=wl&sig=t%2BbzU9%2B7ry4okULN9S0wst%2F8MCUhTjrHyV9rDNLSe8g%3D
Once you have run the code, the shared access signature you created for the container will be valid for the next 24 hours. The signature grants a client permission to list blobs in the container and to write new blobs to the container.
Next, we write similar code to create a new blob within the container and generate a shared access signature for it. This shared access signature is not associated with a stored access policy, so it includes the start time, expiry time, and permission information in the URI.
Add a new method that creates a new blob and writes some text to it, then generates a shared access signature and returns the signature URI:
static string GetBlobSasUri(CloudBlobContainer container)
{
//Get a reference to a blob within the container.
CloudBlockBlob blob = container.GetBlockBlobReference("sasblob.txt");
//Upload text to the blob. If the blob does not yet exist, it will be created.
//If the blob does exist, its existing content will be overwritten.
string blobContent = "This blob will be accessible to clients via a shared access signature (SAS).";
blob.UploadText(blobContent);
//Set the expiry time and permissions for the blob.
//In this case, the start time is specified as a few minutes in the past, to mitigate clock skew.
//The shared access signature will be valid immediately.
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessStartTime = DateTimeOffset.UtcNow.AddMinutes(-5);
sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24);
sasConstraints.Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write;
//Generate the shared access signature on the blob, setting the constraints directly on the signature.
string sasBlobToken = blob.GetSharedAccessSignature(sasConstraints);
//Return the URI string for the container, including the SAS token.
return blob.Uri + sasBlobToken;
}
At the bottom of the Main() method, add the following lines to call GetBlobSasUri(), before the call to Console.ReadLine(), and write the shared access signature URI to the console window:
//Generate a SAS URI for a blob within the container, without a stored access policy.
Console.WriteLine("Blob SAS URI: " + GetBlobSasUri(container));
Console.WriteLine();
Compile and run to output the shared access signature URI for the new blob. The URI will be similar to the following:
https://storageaccount.blob.core.windows.net/sascontainer/sasblob.txt?sv=2012-02-12&st=2013-04-12T23%3A37%3A08Z&se=2013-04-13T00%3A12%3A08Z&sr=b&sp=rw&sig=dF2064yHtc8RusQLvkQFPItYdeOz3zR8zHsDMBi4S30%3D
Now let's create a stored access policy on the container, which will define the constraints for any shared access signatures that are associated with it.
In the previous examples, we specified the start time (implicitly or explicitly), the expiry time, and the permissions on the shared access signature URI itself. In the following examples, we specify these on the stored access policy, not on the shared access signature. Doing so enables us to change these constraints without reissuing the shared access signature.
It's possible to have one or more of the constraints on the shared access signature, and the remainder on the stored access policy. However, you can only specify the start time, expiry time, and permissions in one place or the other. For example, you can't specify permissions on the shared access signature and also specify them on the stored access policy.
When you add a stored access policy to a container, you must get the container's existing permissions, add the new access policy, and then set the container's permissions.
Add a new method that creates a new stored access policy on a container and returns the name of the policy:
static void CreateSharedAccessPolicy(CloudBlobClient blobClient, CloudBlobContainer container,
string policyName)
{
//Get the container's existing permissions.
BlobContainerPermissions permissions = container.GetPermissions();
//Create a new shared access policy and define its constraints.
SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
{
SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24),
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List | SharedAccessBlobPermissions.Read
};
//Add the new policy to the container's permissions, and set the container's permissions.
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
container.SetPermissions(permissions);
}
At the bottom of the Main() method, before the call to Console.ReadLine(), add the following lines to first clear any existing access policies, and then call the CreateSharedAccessPolicy() method:
//Clear any existing access policies on container.
BlobContainerPermissions perms = container.GetPermissions();
perms.SharedAccessPolicies.Clear();
container.SetPermissions(perms);
//Create a new access policy on the container, which may be optionally used to provide constraints for
//shared access signatures on the container and the blob.
string sharedAccessPolicyName = "tutorialpolicy";
CreateSharedAccessPolicy(blobClient, container, sharedAccessPolicyName);
When you clear the access policies on a container, you must first get the container's existing permissions, then clear the permissions, then set the permissions again.
Next, we create another shared access signature for the container that we created earlier, but this time we associate the signature with the stored access policy we created in the previous example.
Add a new method to generate another shared access signature for the container:
static string GetContainerSasUriWithPolicy(CloudBlobContainer container, string policyName)
{
//Generate the shared access signature on the container. In this case, all of the constraints for the
//shared access signature are specified on the stored access policy.
string sasContainerToken = container.GetSharedAccessSignature(null, policyName);
//Return the URI string for the container, including the SAS token.
return container.Uri + sasContainerToken;
}
At the bottom of the Main() method, before the call to Console.ReadLine(), add the following lines to call the GetContainerSasUriWithPolicy method:
//Generate a SAS URI for the container, using a stored access policy to set constraints on the SAS.
Console.WriteLine("Container SAS URI using stored access policy: " + GetContainerSasUriWithPolicy(container, sharedAccessPolicyName));
Console.WriteLine();
Finally, we add a similar method to create another blob and generate a shared access signature that's associated with a stored access policy.
Add a new method to create a blob and generate a shared access signature:
static string GetBlobSasUriWithPolicy(CloudBlobContainer container, string policyName)
{
//Get a reference to a blob within the container.
CloudBlockBlob blob = container.GetBlockBlobReference("sasblobpolicy.txt");
//Upload text to the blob. If the blob does not yet exist, it will be created.
//If the blob does exist, its existing content will be overwritten.
string blobContent = "This blob will be accessible to clients via a shared access signature. " +
"A stored access policy defines the constraints for the signature.";
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(blobContent));
ms.Position = 0;
using (ms)
{
blob.UploadFromStream(ms);
}
//Generate the shared access signature on the blob.
string sasBlobToken = blob.GetSharedAccessSignature(null, policyName);
//Return the URI string for the container, including the SAS token.
return blob.Uri + sasBlobToken;
}
At the bottom of the Main() method, before the call to Console.ReadLine(), add the following lines to call the GetBlobSasUriWithPolicy method:
//Generate a SAS URI for a blob within the container, using a stored access policy to set constraints on the SAS.
Console.WriteLine("Blob SAS URI using stored access policy: " + GetBlobSasUriWithPolicy(container, sharedAccessPolicyName));
Console.WriteLine();
The Main() method should now look like this in its entirety. Run it to write the shared access signature URIs to the console window, then copy and paste them into a text file for use in the second part of this tutorial.
static void Main(string[] args)
{
//Parse the connection string and return a reference to the storage account.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
//Create the blob client object.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
//Get a reference to a container to use for the sample code, and create it if it does not exist.
CloudBlobContainer container = blobClient.GetContainerReference("sascontainer");
container.CreateIfNotExists();
//Generate a SAS URI for the container, without a stored access policy.
Console.WriteLine("Container SAS URI: " + GetContainerSasUri(container));
Console.WriteLine();
//Generate a SAS URI for a blob within the container, without a stored access policy.
Console.WriteLine("Blob SAS URI: " + GetBlobSasUri(container));
Console.WriteLine();
//Clear any existing access policies on container.
BlobContainerPermissions perms = container.GetPermissions();
perms.SharedAccessPolicies.Clear();
container.SetPermissions(perms);
//Create a new access policy on the container, which may be optionally used to provide constraints for
//shared access signatures on the container and the blob.
string sharedAccessPolicyName = "tutorialpolicy";
CreateSharedAccessPolicy(blobClient, container, sharedAccessPolicyName);
//Generate a SAS URI for the container, using a stored access policy to set constraints on the SAS.
Console.WriteLine("Container SAS URI using stored access policy: " + GetContainerSasUriWithPolicy(container, sharedAccessPolicyName));
Console.WriteLine();
//Generate a SAS URI for a blob within the container, using a stored access policy to set constraints on the SAS.
Console.WriteLine("Blob SAS URI using stored access policy: " + GetBlobSasUriWithPolicy(container, sharedAccessPolicyName));
Console.WriteLine();
Console.ReadLine();
}
When you run the GenerateSharedAccessSignatures console application, you'll see output similar to the following. These are the shared access signatures you use in Part 2 of the tutorial.
Container SAS URI: https://storagesample.blob.core.windows.net/sascontainer?sv=2016-05-31&sr=c&sig=pFlEZD%2F6sJTNLxD%2FQ26Hh85j%2FzYPxZav6mP1KJwnvJE%3D&se=2017-05-16T16%3A16%3A47Z&sp=wl
Blob SAS URI: https://storagesample.blob.core.windows.net/sascontainer/sasblob.txt?sv=2016-05-31&sr=b&sig=%2FiBWAZbXESzCMvRcm7JwJBK0gT0BtPSWEq4pRwmlBRI%3D&st=2017-05-15T16%3A11%3A48Z&se=2017-05-16T16%3A16%3A48Z&sp=rw
Container SAS URI using stored access policy: https://storagesample.blob.core.windows.net/sascontainer?sv=2016-05-31&sr=c&si=tutorialpolicy&sig=aMb6rKDvvpfiGVsZI2rCmyUra6ZPpq%2BZ%2FLyTgAeec%2Bk%3D
Blob SAS URI using stored access policy: https://storagesample.blob.core.windows.net/sascontainer/sasblobpolicy.txt?sv=2016-05-31&sr=b&si=tutorialpolicy&sig=%2FkTWkT23SS45%2FoF4bK2mqXkN%2BPKs%2FyHuzkfQ4GFoZVU%3D
To test the shared access signatures created in the previous examples, we create a second console application that uses the signatures to perform operations on the container and on a blob.
Note
If more than 24 hours have passed since you completed the first part of the tutorial, the signatures you generated will no longer be valid. In this case, you should run the code in the first console application to generate fresh shared access signatures for use in the second part of the tutorial.
In Visual Studio, create a new Windows console application and name it ConsumeSharedAccessSignatures. Add references to Microsoft.WindowsAzure.ConfigurationManager and WindowsAzure.Storage, as you did previously.
At the top of the Program.cs file, add the following using directives:
using System.IO;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
In the body of the Main() method, add the following string constants, changing their values to the shared access signatures you generated in part 1 of the tutorial.
static void Main(string[] args)
{
const string containerSAS = "<your container SAS>";
const string blobSAS = "<your blob SAS>";
const string containerSASWithAccessPolicy = "<your container SAS with access policy>";
const string blobSASWithAccessPolicy = "<your blob SAS with access policy>";
}
Next, we add a method that tests some container operations using a shared access signature for the container. The shared access signature is used to return a reference to the container, authenticating access to the container based on the signature alone.
Add the following method to Program.cs:
static void UseContainerSAS(string sas)
{
//Try performing container operations with the SAS provided.
//Return a reference to the container using the SAS URI.
CloudBlobContainer container = new CloudBlobContainer(new Uri(sas));
//Create a list to store blob URIs returned by a listing operation on the container.
List<ICloudBlob> blobList = new List<ICloudBlob>();
//Write operation: write a new blob to the container.
try
{
CloudBlockBlob blob = container.GetBlockBlobReference("blobCreatedViaSAS.txt");
string blobContent = "This blob was created with a shared access signature granting write permissions to the container. ";
blob.UploadText(blobContent);
Console.WriteLine("Write operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("Write operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
//List operation: List the blobs in the container.
try
{
foreach (ICloudBlob blob in container.ListBlobs())
{
blobList.Add(blob);
}
Console.WriteLine("List operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("List operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
//Read operation: Get a reference to one of the blobs in the container and read it.
try
{
CloudBlockBlob blob = container.GetBlockBlobReference(blobList[0].Name);
MemoryStream msRead = new MemoryStream();
msRead.Position = 0;
using (msRead)
{
blob.DownloadToStream(msRead);
Console.WriteLine(msRead.Length);
}
Console.WriteLine("Read operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("Read operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
Console.WriteLine();
//Delete operation: Delete a blob in the container.
try
{
CloudBlockBlob blob = container.GetBlockBlobReference(blobList[0].Name);
blob.Delete();
Console.WriteLine("Delete operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("Delete operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
}
Update the Main() method to call UseContainerSAS() with both of the shared access signatures you created on the container:
static void Main(string[] args)
{
string containerSAS = "<your container SAS>";
string blobSAS = "<your blob SAS>";
string containerSASWithAccessPolicy = "<your container SAS with access policy>";
string blobSASWithAccessPolicy = "<your blob SAS with access policy>";
//Call the test methods with the shared access signatures created on the container, with and without the access policy.
UseContainerSAS(containerSAS);
UseContainerSAS(containerSASWithAccessPolicy);
Console.ReadLine();
}
Finally, we add a method that tests some blob operations using a shared access signature on the blob. In this case, we use the constructor CloudBlockBlob(String), passing in the shared access signature, to return a reference to the blob. No other authentication is required; it's based on the signature alone.
Add the following method to Program.cs:
static void UseBlobSAS(string sas)
{
//Try performing blob operations using the SAS provided.
//Return a reference to the blob using the SAS URI.
CloudBlockBlob blob = new CloudBlockBlob(new Uri(sas));
//Write operation: Write a new blob to the container.
try
{
string blobContent = "This blob was created with a shared access signature granting write permissions to the blob. ";
MemoryStream msWrite = new MemoryStream(Encoding.UTF8.GetBytes(blobContent));
msWrite.Position = 0;
using (msWrite)
{
blob.UploadFromStream(msWrite);
}
Console.WriteLine("Write operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("Write operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
//Read operation: Read the contents of the blob.
try
{
MemoryStream msRead = new MemoryStream();
using (msRead)
{
blob.DownloadToStream(msRead);
msRead.Position = 0;
using (StreamReader reader = new StreamReader(msRead, true))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
Console.WriteLine("Read operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("Read operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
//Delete operation: Delete the blob.
try
{
blob.Delete();
Console.WriteLine("Delete operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (StorageException e)
{
Console.WriteLine("Delete operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
}
Update the Main() method to call UseBlobSAS() with both of the shared access signatures that you created on the blob:
static void Main(string[] args)
{
string containerSAS = "<your container SAS>";
string blobSAS = "<your blob SAS>";
string containerSASWithAccessPolicy = "<your container SAS with access policy>";
string blobSASWithAccessPolicy = "<your blob SAS with access policy>";
//Call the test methods with the shared access signatures created on the container, with and without the access policy.
UseContainerSAS(containerSAS);
UseContainerSAS(containerSASWithAccessPolicy);
//Call the test methods with the shared access signatures created on the blob, with and without the access policy.
UseBlobSAS(blobSAS);
UseBlobSAS(blobSASWithAccessPolicy);
Console.ReadLine();
}
Run the console application and observe the output to see which operations are permitted for which signatures. The output in the console window will look similar to the following:
Write operation succeeded for SAS https://storagesample.blob.core.windows.net/sascontainer?sv=2016-05-31&sr=c&sig=32EaQGuFyDMb3yOAey3wq%2B%2FLwgPQxAgSo7UhzLdyIDU%3D&se=2017-05-16T15%3A41%3A20Z&sp=wl
List operation succeeded for SAS https://storagesample.blob.core.windows.net/sascontainer?sv=2016-05-31&sr=c&sig=32EaQGuFyDMb3yOAey3wq%2B%2FLwgPQxAgSo7UhzLdyIDU%3D&se=2017-05-16T15%3A41%3A20Z&sp=wl
Read operation failed for SAS https://storagesample.blob.core.windows.net/sascontainer?sv=2016-05-31&sr=c&sig=32EaQGuFyDMb3yOAey3wq%2B%2FLwgPQxAgSo7UhzLdyIDU%3D&se=2017-05-16T15%3A41%3A20Z&sp=wl
Additional error information: The remote server returned an error: (403) Forbidden.
Delete operation failed for SAS https://storagesample.blob.core.windows.net/sascontainer?sv=2016-05-31&sr=c&sig=32EaQGuFyDMb3yOAey3wq%2B%2FLwgPQxAgSo7UhzLdyIDU%3D&se=2017-05-16T15%3A41%3A20Z&sp=wl
Additional error information: The remote server returned an error: (403) Forbidden.
...