Search code examples
azuresasazure-blob-storagetokenazure-storage

Azure SAS token always not authenticated when use by not whitelist IP


my scenario is like this, frontend will hit to API with sending name for blob file, and the backend side in AKS will generate an SAS token for the blob file with expiry time 15 minutes. But when token send to frontend (SPA react) it cannot use have error not authenticated, but when put my browser IP to whitelist I can access the blob file. why this is happen, how to make sas token provide access for public at limited time without whitelist client browser IP?

my error

This XML file does not appear to have any style information associated with it. The document tree is shown below. AuthorizationFailure This request is not authorized to perform this operation. RequestId:b9efa22e-001e-004c-23f9-274133000000 Time:2023-12-06T04:07:47.4688222Z

this is my code look like

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Azure.Storage.Blobs;
using Azure.Storage.Sas;
using System;
using Azure.Storage;

namespace SAS.Container.Controllers
{
    [ApiController]
    [Route("api/get-sas")]
    public class GetSasAzureStorageController : ControllerBase
    {
        private readonly IConfiguration _configuration;

        public GetSasAzureStorageController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

       [HttpGet("")]
        public IActionResult GetSasToken()
        {
            try
            {
                string connectionString = _configuration.GetConnectionString("AzureStorageConnection");

                if (string.IsNullOrEmpty(connectionString))
                {
                    return BadRequest("AzureStorageConnection is not configured in appsettings.json");
                }
                
                BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
                string containerName = "assets";
                string blobName = "myblob.png";
                var accountKey="myaccountKey";
               
                BlobClient blobClient = blobServiceClient.GetBlobContainerClient(containerName).GetBlobClient(blobName);

                // Set permissions for SAS token
                BlobSasBuilder sasBuilder = new BlobSasBuilder()
                {
                    BlobContainerName = containerName,
                    BlobName = blobName,
                    Resource = "b", // 'b' for blob
                    StartsOn = DateTimeOffset.UtcNow,
                    ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(15)
                };

                // set permission read for SAS token
                sasBuilder.SetPermissions(BlobSasPermissions.Read);

                // Generate SAS token
                BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
                {
                    Sas = sasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(blobServiceClient.AccountName,accountKey ))
                };
                var sastoken = blobUriBuilder.ToUri().ToString();
                return Ok(new
                {
                     sastoken
                });
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred: {ex.Message}");
            }
        }
    }
}

Solution

  • How to make the sas token provide access for the public at a limited time without whitelisting the client browser IP?

    If you need to access the SAS token for the public at a limited time without whitelisting the client browser IP, you need to change your network settings.

    If your networking is enabled for selected virtual networks and IP addresses you can't able to access them in public.

    Portal -> your storage accounts -> Networking ->select the Enabled from all networks from portal.

    Portal: enter image description here

    Now you can use the same code to generate a SAS token to display the image.

    Code:

    var AccountName = "xxx";
    var AccountKey = "xxxx";
    var containerName = "xxxx";
    var blobName = "xxxx";
    StorageSharedKeyCredential key = new StorageSharedKeyCredential(AccountName, AccountKey);
    BlobServiceClient blobServiceClient = new BlobServiceClient(new Uri($"https://{AccountName}.blob.core.windows.net"), key);
    BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
    BlobClient blobClient = containerClient.GetBlobClient(blobName);
    
    var sasBuilder = new BlobSasBuilder()
    {
        BlobContainerName = containerName,
        BlobName = blobName,
        Resource = "b", // b for blob, c for container
        StartsOn = DateTimeOffset.UtcNow,
        ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(15),
    };
    sasBuilder.SetPermissions(BlobSasPermissions.All); // All permissions like(Read,write,add,list,create,SetImmutabilityPolicy,delete)
    var Sas = sasBuilder.ToSasQueryParameters(key).ToString();
    Console.WriteLine(Sas);
    var sasuri = blobClient.Uri.AbsoluteUri + "?" + Sas;
    Console.WriteLine(sasuri);
    

    Output:

    SAStoken = sv=2023-11-03&st=2023-12-07T07%3A00%3A17Z&se=2023-12-07T07%3A15%3A17Z&sr=b&sp=racwdxyltmei&sig=xxx
    BlobSASUrl = https://venkat789.blob.core.windows.net/demo/spring-flowers.jpg?sv=2023-11-03&st=2023-12-07T07%3A00%3A17Z&se=2023-12-07T07%3A15%3A17Z&sr=b&sp=racwdxyltmei&sig=xxxxx
    

    Copied the BlobSASUrl and pasted it into the browser it worked perfectly in public with 15 minutes expiry time.

    Browser: enter image description here