There are several use cases where we need to share the azure resources with limited access based on some conditions. SAS tokens provide a flexible and secure way to grant temporary access to Azure storage resources without compromising the security of the storage account.

In this article we will explore shared access signature, SAS tokens, a secure way to share the azure resources. Furthermore, I will demonstrate how to generate SAS tokens with a complete solution using Blazor Apps in .NET 7. For this demo, I will use azure blob storage files with a view URL using SAS token.

Uploading files or attachments is one of the common requirements for any application. Azure storage is one of the most efficient cloud storage with all the necessary features, security, and compliance. Azure Storage, a platform owned by Microsoft, is a contemporary cloud storage solution for almost every case scenario that is highly secure, scalable, durable, and easy to manage.

In this article, we learn about SRS token for Azure Blob Storage files and will demonstrate with code in Blazor Application using .NET 7.

  • What is a shared access signature, SAS?
  • What is Azure Storage?
  • How to create an Azure Storage Account?
  • What is a Blazor Web App
  • Create a Blazor App with .Net 7
  • Upload and delete files in Azure Blobs using a Blazor App in .NET 7
  • Create a SAS token and view URL for Azure Blob Files using Blazor App

Full source code GitHub: Upload, delete, Generate SAS Token and View URL

What is an SAS Token?

A SAS (Shared Access Signature) token is a secure way to grant limited access to resources in Azure storage. It provides a way to grant temporary access to a resource without sharing the account keys. With a SAS token, you can define the permissions (such as read, write, or delete) and the time interval for which access is permitted. This allows you to control access to your azure resources and lessen the risk of unauthorized access.

SAS tokens can be generated for various resources in Azure storage, including blobs, files, queues, and tables. They are created using the storage account key, but the token itself is not a key and can be safely shared with others.

To use an SAS token, the client must include it in the request to Azure storage. The SAS token is included as a query parameter in the URL of the request. The token can also be embedded in a connection string for use by client libraries.

How to generate SAS Token?

SAS token can be generated using various methods: Azure Portal, Azure Storage Explorer, Azure PowerShell, or Azure CLI, and programmatically using Azure SDK. In this article, I will demonstrate using azure SDK with .Net, however, we can use other programming languages.

While generating the SAS token, we can define the permissions, and expiry duration.

Azure Storage

Azure Storage is a modern cloud storage solution owned by Microsoft, for almost every data storage scenario that is highly secure, scalable, durable, and easy to manage. It is well managed for hardware, updates, critical issues, high availability and is accessible from any part of the globe. Furthermore, the Azure UI is user-friendly, and we can create the services/objects effortlessly with all the configuration features. Additionally, Azure Storage provides all the necessary client libraries/SDK in .NET, Python, JavaScript, Java C++, PHP, Node.js, Ruby, Go, therefore developers can simply implement in their applications using the programming language of their choice. We can even access the storage objects via HTTP, HTTPS or REST API. Azure CLI or Azure PowerShell can be used by IT professionals to create scripts for those services and configuration tasks.
To know more details: Click Here

Azure Storage Data Services

Azure storage consists of 5 data services, as portrayed in the above diagram.

  • Azure Blob Storage
  • Azure Files
  • Azure Tables
  • Azure Queues

In my previous article, I illustrated and shared the step-by-step process to create an Azure Storage account. 

Upload and Delete files in Azure Blob Storage Using Blazor Apps With .NET 7

In this write-up, I will delve on how to create SAS token and azure storage files to view URL programmatically using Blazor Apps with .NET.

Prerequisites

  • Visual Studio 2022
  • .NET 7
  • Azure Subscription (You can create trial subscription)
  • C# Knowledge

Create Azure Storage Account

Azure storage account provides a unique namespace in the cloud for our azure storage that contains all the azure data storage components including Blob storage, Azure Files, Azure Tables, Azure Queues, and disks and can be accessible through authenticate HTTP(S) calls.

https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview

Please refer to my previous article to create a storage account and container. Click Here.

Install .NET 7 SDK

We can use any version of Visual Studio 2022, and we can download from this link. You can use the community version, which is free. Additionally, you can download .NET 7 SDK for free from this official site. In my case, I am using Visual Studio 2022 Professional, however, the steps and interfaces are the same for other versions.

Create a Web App with Blazor Server

Blazor server runs as an implementation of server side as a part of ASP.NET core app where UI events, button clicks, UI updates and interactions are communicated over SignalR connection. In this approach, the UI is generated on a web server and is transmitted to the visitor’s browser upon request. This two-way interaction occurs using SignalR and a web sockets connection. Any change in DOM content is generated from web server and update in automatically via SignalR with Blazor Server framework. This Blazor type has direct access to server and network resources since app is executed in server side. Let’s open a Visual Studio and create a new project. We will use the Blazor Server App project template.

We provide a project name and location for the solution.

On the next screen, we will get options to choose .Net framework, Authentication type and a couple options for the project.

After installation of .NET 7 SDK, we will have an option to choose .NET 7 in the framework. We will select the .NET 7 framework and proceed. To keep it simple, we will keep other options default.

We have successfully created a Blazor server web application with .NET 7. We will build and run the solution.

This is how we can create a Blazor server app.

Upload and Delete Files in Azure Blob Storage Using Blazor App with .NET 7

In my previous article, I demonstrated a complete solution to upload and delete files in Azure Blob Storage. Click Here.

In this article, I will show how to create a SAS token and view URLs with the same solution. Storage account and access key are required to generate the SAS token.

Access Keys

Login to Azure Portal, Navigate to Azure Storage Account and click Access Key as portrayed.

Now we will add a storage account and access key into the app setting file as shown below.

Code:

We will define another function for generating SAS token URL in IBlogStorageService Interface, named, GetBlobSASTOkenByFile.

Task<string> GetBlobSASTOkenByFile(string fileName);

Implementation of the above function in BlogStorageService is as shown below.

Code:

Code:

 public async Task<string> GetBlobSASTOkenByFile(string fileName)
    {
        try
        {
            var azureStorageAccount = _configuration.GetSection("AzureStorage:AzureAccount").Value;
            var azureStorageAccessKey = _configuration.GetSection("AzureStorage:AccessKey").Value;
            Azure.Storage.Sas.BlobSasBuilder blobSasBuilder = new Azure.Storage.Sas.BlobSasBuilder()
            {
                BlobContainerName = blobContainerName,
                BlobName = fileName,
                ExpiresOn = DateTime.UtcNow.AddMinutes(2),//Let SAS token expire after 5 minutes.
            };
            blobSasBuilder.SetPermissions(Azure.Storage.Sas.BlobSasPermissions.Read);//User will only be able to read the blob and it's properties
            var sasToken = blobSasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(azureStorageAccount,
                azureStorageAccessKey)).ToString();
            return sasToken;
        }
        catch (Exception)
        {

            throw;
        }
    }

The above function will generate our SAS token, which can be used to allow the access of azure resources. The token can be used to view the files.

Please note, we can set expiry and permissions while generating SAS token in the parameter as highlighted.

Example SAS token generated from above function.

sv=2021-10-04&se=2023-03-20T11%3A20%3A45Z&sr=b&sp=r&sig=M5GaoRgyIWcLMMfggqfZ9pI01dZLyFD0Em5WdCNsUuk%3D

We will update the Blazor component to view the file with SAS token.

We will use a view icon with the below function.

Code:

private async void OnFileViewClick(FileUploadViewModel attachment)
    {
        try
        {
            var sasToken = await blobStorageService.GetBlobSASTOkenByFile(attachment.FileName);
            if (sasToken != null)
            {
                string fileUrl = attachment.FileStorageUrl + "?" + sasToken;
                await jsRuntime.InvokeAsync<object>("open", fileUrl, "_blank");
            }

        }
        catch (Exception)
        {
            warninngMessage = "Something went wrong! Please try again.";
        }
        this.StateHasChanged();
    }

We need to inject JSRunTime.

@inject IJSRuntime jsRuntime

Complete Blazor Page Code.

@page "/"
@using RijsatFileUploadAzureStorage.Services;
@using RijsatFileUploadAzureStorage.Services.Dto;
@inject IBlobStorageService blobStorageService
@inject IJSRuntime jsRuntime

<PageTitle>Index</PageTitle>
@if (warninngMessage.Length > 0)
{
    <div class="alert alert-warning">
        <strong>Warning!</strong> @warninngMessage.
    </div>
}

<h4>File Upload (Azure Blob Storage)</h4>
<div class="row">
    <div class="col-sm-6">
        <label>
            <InputFile class="form-control" disabled="@fileLoading" OnChange="@OnInputFileChange" single />
        </label>
        @if (fileLoading)
        {
            <i class="fa fa-refresh"></i> <span>Loading...</span>
        }
    </div>
    <div class="col-sm-2">
        <button type="button" disabled="@fileLoading" class="btn btn-primary" @onclick="OnUploadSubmit">
            Upload File
        </button>
    </div>
</div>
@if (displayMessage.Length > 0)
{
    <div class="alert alert-success">
        <strong>Success!</strong> @displayMessage.
    </div>
}
<br />
<div class="row">
    @if (fileUploadViewModels.Count > 0)
    {
        <table class="table table-responsive table-bordered">
            <thead class="text-primary">
                <tr>
                    <th>File</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var attachment in fileUploadViewModels)
                {

                    <tr>
                        <td>
                            <a class="text-primary"><i class="fa-solid fa-paperclip"></i> @attachment.FileName</a>
                        </td>

                        <td>
                            <span class="oi oi-delete" aria-hidden="true" @onclick="() => OnFileDeleteClick(attachment)"></span>
                            <span class="oi oi-eye" aria-hidden="true" @onclick="() => OnFileViewClick(attachment)"></span>
                        </td>
                    </tr>
                }
            </tbody>
        </table>
    }
    else
    {
        <div class="alert alert-info">
            <strong>No Files!</strong>
        </div>
    }
</div>

Code

@code {
    private string warninngMessage = "";
    private string displayMessage = "";
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool fileLoading;
    string Message = "No file(s) selected";
    IReadOnlyList<IBrowserFile> selectedFiles;
    private List<FileUploadViewModel> fileUploadViewModels = new();
    private void OnInputFileChange(InputFileChangeEventArgs e)
    {
        selectedFiles = e.GetMultipleFiles();
        Message = $"{selectedFiles.Count} file(s) selected";
        this.StateHasChanged();
    }
    private async void OnUploadSubmit()
    {
        fileLoading = true;
        foreach (var file in selectedFiles)
        {
            try
            {
                var trustedFileNameForFileStorage = file.Name;
                var blobUrl = await blobStorageService.UploadFileToBlobAsync(trustedFileNameForFileStorage, file.ContentType, file.OpenReadStream(20971520));
                if (blobUrl != null)
                {
                    FileUploadViewModel fileUploadViewModel = new FileUploadViewModel()
                        {
                            FileName = trustedFileNameForFileStorage,
                            FileStorageUrl = blobUrl,
                            ContentType = file.ContentType,
                        };

                    fileUploadViewModels.Add(fileUploadViewModel);
                    displayMessage = trustedFileNameForFileStorage + " Uploaded!!";
                }
                else
                    warninngMessage = "File Upload failed, Please try again!!";

            }
            catch (Exception ex)
            {
                warninngMessage = "File Upload failed, Please try again!!";
            }
        }

        fileLoading = false;
        this.StateHasChanged();
    }

    private async void OnFileDeleteClick(FileUploadViewModel attachment)
    {
        try
        {
            var deleteResponse = await blobStorageService.DeleteFileToBlobAsync(attachment.FileName);
            if (deleteResponse)
            {
                fileUploadViewModels.Remove(attachment);
                displayMessage = attachment.FileName + " Deleted!!";
            }

        }
        catch (Exception)
        {
            warninngMessage = "Something went wrong! Please try again.";
        }
        this.StateHasChanged();
    }
    private async void OnFileViewClick(FileUploadViewModel attachment)
    {
        try
        {
            var sasToken = await blobStorageService.GetBlobSASTOkenByFile(attachment.FileName);
            if (sasToken != null)
            {
                string fileUrl = attachment.FileStorageUrl + "?" + sasToken;
                await jsRuntime.InvokeAsync<object>("open", fileUrl, "_blank");
            }

        }
        catch (Exception)
        {
            warninngMessage = "Something went wrong! Please try again.";
        }
        this.StateHasChanged();
    }

}

Let’s run the application and test it. 

First, I will upload a file.

Then, I will click on the view icon.

Thus, we can view the azure blob files using SAS token.

The view URL will be a combination of the azure blob storage and SAS token.

View URL = blogstorageURL + SAS Token

Full source code GitHub: Upload, delete, Generate SAS Token and View URL

Conclusion

SAS is a flexible and secure way to grant temporary access to azure storage resources without compromising the security. We can add permissions and expire with SAS token. In this article, I have explored SAS token and methods to generate it. In my previous article, I show how to upload and delete the azure blob storage files using Blazor apps and .NET 7. This article is a continuation of the article where I have shown how to create SAS token and view files using Blazor apps and .NET 7. I have demonstrated with examples and a complete solution is available in GitHub (Shared).  

By Rijwan Ansari

Research and Technology Lead | Software Architect | Full Stack .NET Expert | Tech Blogger | Community Speaker | Trainer | YouTuber. Follow me @ https://rijsat.com Md Rijwan Ansari is a high performing and technology consultant with 10 plus years of Software Development and Business Applications implementation using .NET Technologies, SharePoint, Power Platform, Data, AI, Azure and cognitive services. He is also a Microsoft Certified Trainer, C# Corner MVP, Microsoft Certified Data Analyst Associate, Microsoft Certified Azure Data Scientist Associate, CSM, CSPO, MCTS, MCP, with 15+ Microsoft Certifications. He is a research and technology lead in Tech One Global as well as leading Facebook community Cloud Experts Group and SharePoint User Group Nepal. He is a active contributor and speaker in c-sharpcorner.com community, C# Corner MVP and his rank at 20 among 3+ millions members. Additionally, he is knee to learn new technologies, write articles, love to contribute to the open-source community. Visit his blog RIJSAT.COM for extensive articles, courses, news, videos and issues resolution specially for developer and data engineer.

Leave a Reply

Your email address will not be published. Required fields are marked *