Search code examples
azureazure-functionsazure-blob-storageazure-logic-apps

How can I create a Blob file SAS URI using Azure Functions with the HTTP Trigger?


I am currently working on a project where we have the requirement to create blob files from base64 using Logic Apps.

The Blob files that are being created also need a SAS URI generated that last for a certain amount of time.

When we try to 'secure' the blob container using IP Restriction, the OOB Blob Connector won't connect to the Storage Account to create the SAS URI.

We would like to trigger an Azure Function from the Logic App that takes in Dynamic Data from the Logic App in the HTTP Trigger Body, creates the SAS URI for that specific blob file and returns the SAS URI back to the logic app so we can process this further.

Please note that I do not have any experience in C# and the following code is basically something that is constructed using research :)

However, it doesn't really work. Can somebody take a look at this and show me what I am missing?

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Azure.Storage.Blobs;
using Azure.Storage.Sas;
using Azure.Storage;
using System.Reflection.Metadata;


namespace SasURIGeneration
{
    public static class SasUriGenerator
    {
        [FunctionName("SasUriGenerator")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("The SAS URI Generator has processed an incoming request");

            string blobName = req.Query["blobName"];
            string storageContainer = req.Query["storageContainer"];
            string storageAccount = req.Query["storageAccount"];
            string connectionString = req.Query["connectionString"];
            string accountKey = req.Query["accountKey"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); //reads the requestbody
            dynamic data = JsonConvert.DeserializeObject(requestBody); //Microsoft built in JSON Converter, deserializes the body into a dynamic object


            //TO DO - Do something with the data under this line!!
            BlobContainerClient blobContainerClient = new BlobContainerClient(connectionString,storageContainer);


            BlobClient blobClient = blobContainerClient.GetBlobClient(blobName);

            Azure.Storage.Sas.BlobSasBuilder blobSasBuilder = new Azure.Storage.Sas.BlobSasBuilder()
            {
                BlobContainerName = storageContainer,
                BlobName = blobName,
                ExpiresOn = DateTime.UtcNow.AddMinutes(5),//Let SAS token expire after 5 minutes.
            };
            blobSasBuilder.SetPermissions(BlobSasPermissions.Read);//User will only be able to read the blob and it's properties
            var sasToken = blobSasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(storageAccount, accountKey)).ToString();
            var sasURL = $"{blobClient.Uri.AbsoluteUri}?{sasToken}";

            Console.WriteLine(sasURL);
            log.LogInformation($"Generated SAS URI: {sasURL}");
            return new OkObjectResult(sasURL);




        }
    }
}

Any help / best-practices would be very much appreciated :)

I tried to generate the SAS URI based on the blobName, storageContainer in the HTTP trigger body but when I run the following code I get an error that 'connectionString' cannot be null.


Solution

  • In order to generate SAS URI for the specific blob that you are getting from Logic App in Azure Functions Http Trigger refer the code below:-

    My Function1.cs:-

    using System;
    using System.Net;
    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.Extensions.Logging;
    using Azure.Storage;
    using Azure.Storage.Blobs;
    using Azure.Storage.Sas;
    
    namespace FunctionApp68
    {
        public class Function1
        {
            private readonly ILogger _logger;
    
            public Function1(ILoggerFactory loggerFactory)
            {
                _logger = loggerFactory.CreateLogger<Function1>();
            }
    
            [Function("Function1")]
            public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
            {
                _logger.LogInformation("C# HTTP trigger function processed a request.");
    
                var response = req.CreateResponse(HttpStatusCode.OK);
                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
    
                // Your storage account credentials and blob information
                string connectionString = "DefaultEndpointsProtocol=https;AccountName=valleystrg78;AccountKey=DKmndD4v/s5pQF4BghjwtQg3qk3tDxar/QJt6vFVI9ObYGqgGDefgCvAJdFor0QatMx5BzVjK+4M+ASt5Uxsag==;EndpointSuffix=core.windows.net";
                string storageContainer = "data";
                string blobName = "parameters.txt";
                string storageAccount = "valleystrg78";
                string accountKey = "DKmndD4v/s5pQF4BghjwtQg3qk3tDxar/QJt6vFVI9ObYGqgGDefgCvAJdFor0QatMx5BzVjK+4M+ASt5Uxsag==";
    
                // Create a BlobServiceClient using the connection string
                BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
    
                // Get a reference to the blob container
                BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(storageContainer);
    
                // Get a reference to the blob
                BlobClient blobClient = blobContainerClient.GetBlobClient(blobName);
    
                // Create BlobSasBuilder to generate SAS token
                BlobSasBuilder blobSasBuilder = new BlobSasBuilder()
                {
                    BlobContainerName = storageContainer,
                    BlobName = blobName,
                    ExpiresOn = DateTime.UtcNow.AddMinutes(5), // Let SAS token expire after 5 minutes
                };
                blobSasBuilder.SetPermissions(BlobSasPermissions.Read); // User will only be able to read the blob and its properties
    
                // Generate SAS token
                var sasToken = blobSasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(storageAccount, accountKey)).ToString();
    
                // Append SAS token to blob URI to create SAS URI
                var blobSasUri = $"{blobClient.Uri}?{sasToken}";
    
                response.WriteString($"Blob SAS URI: {blobSasUri}");
    
                return response;
            }
        }
    }
    

    Output:-

    enter image description here

    Received SAS URI successfully in the Http Response:-

    enter image description here

    Reference:-

    azure-docs/articles/storage/blobs/sas-service-create-dotnet.md at main · MicrosoftDocs/azure-docs (github.com)