Search code examples
azureazure-blob-storageazure-storageazure-storage-accountshared-access-signatures

How to generate SAS toke for blob storage in dart language


I'm currently trying to generate SAS token for blob file in dart language. I took reference from a python code also. In python generate_sas_token() function requires policy id for azure blob storage. where to get this policy_id

This the info I have, Or is there any other way to generate other than generate_sas_token() SDK in python. The reason s I want to create SAS token via dart only. So that I need a flow or method to generate SAS.

Thanks in advance

import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:intl/intl.dart';

String encode_signature(String signature){
  return signature.replaceAll(':', '%3A');
}

String generateSasToken(String accountName, String accountKey, String containerName, String blobName, int expiryHours) {
  var ttl = DateTime.now().add(Duration(hours: expiryHours)).millisecondsSinceEpoch ~/ 1000;
  
  var stringToSign = "r\n${DateFormat("yyyy-MM-ddTHH:mm:ssZ").format(DateTime.now().toUtc())}\n${DateFormat("yyyy-MM-ddTHH:mm:ssZ").format(DateTime.now().add(Duration(hours: expiryHours)).toUtc())}\n/$accountName/$containerName/$blobName\n\n\n\n\n\n\n";
  
  var hmacSha256 = Hmac(sha256, base64.decode(accountKey));
  var signature = base64.encode(hmacSha256.convert(utf8.encode(stringToSign)).bytes);
  
  var queryParams = {
    'sp': 'r',
    'st': DateFormat("yyyy-MM-ddTHH:mm:ssZ").format(DateTime.now().toUtc()),
    'se': DateFormat("yyyy-MM-ddTHH:mm:ssZ").format(DateTime.now().add(Duration(hours: expiryHours)).toUtc()),
    'sv': '2022-11-02',
    'sr': 'b',
    'sig': encode_signature(signature),//Uri.encodeComponent(signature).replaceAll('%3A', ':'), // Encode the signature component
  };

  var queryString = Uri(queryParameters: queryParams).query;

  return queryString;
}

void main() {
  var accountName = "account_name";
  var accountKey = "accountkey";
  var containerName = "azure-webjobs-hosts";
  var blobName = "0_12d6fa4202ac42bdbc33923c413c68ff_1.json";
  var expiryHours = 168;

  var sasToken = generateSasToken(accountName, accountKey, containerName, blobName, expiryHours);
  print(sasToken);
}

this is the code Im running now Im able to get but the only issue is This is the SAS generated in azure portal -

sp=r&st=2024-03-11T06:25:18Z&se=2024-03-11T14:25:18Z&sv=2022-11-02&sr=b&sig=sMX853JrU%2BkgAGgKTXS1XQRvFoh6%2BQQ3jNWRnG8LWVI%3D

This is generated by above code -

sp=r&st=2024-03-14T11%3A56%3A00&se=2024-03-21T11%3A56%3A00&sv=2022-11-02&sr=b&sig=jPsFzl2RoTJNGbMNg%252FwcT1oi%252FyIIBjFJeps1pJyMCGc%253D

Instead of colon ":" I'm getting "%3A". Even though I used replace all function. What could be the issue?

The token is generating but enter image description here

this the timezone in azure portal but when I generate SAS in azure portal it give the following timezone

enter image description here

What would be the issue. The time difference is 5 hours 27 mins approx (minutes variable)

Next issue

I'am able to generate valid SAS token for blob. I used the same for container, but getting 403 error I thought token generation is the problem but later tried with azure portal generated sas token for container still getting the same 403 how it is possible? below is the code I used to get container list

import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;

void main() async {
  final String folderURL = 'https://myblobaccount.blob.core.windows.net/azure-webjobs-hosts?sp=r&st=2024-03-22T07:21:47Z&se=2024-03-22T15:21:47Z&sv=2022-11-02&sr=c&sig=Eg%2B04lD3EWLo2wGocU9mqNjKwqKmo04zSCH0Dbsjqlg%3D';//$storageBlobEndpoint/$containerName?$sasToken';

  // Make a request to list the blobs within the folder
  final response = await http.get(Uri.parse(folderURL));
  if (response.statusCode == 200) {
    final List<dynamic> blobs = json.decode(response.body);
    print("Files in the folder:");
    for (var blob in blobs) {
      print(blob['name']);
    }
  } else {
    print('Failed to fetch data: ${response.statusCode}');
  }
}

what could be the issue?


Solution

  • The code below dart generates a Shared Access Signature (SAS) token for accessing Azure Blob Storage resources. SAS tokens provide restricted access to resources in your storage account, with specified permissions and time limits.

    generateSasToken method:

    it generates a SAS token based on the provided parameters such as resourceUri, key, permissions, sr, and expiryHours.

    import 'dart:convert';
    import 'package:intl/intl.dart';
    import 'package:crypto/crypto.dart';
    
    class SasTokenGenerator {
      String generateSasToken({
        required String resourceUri,
        required String key,
        required String permissions,
        required String sr, // Added parameter for the resource type
        int expiryHours = 24,
      }) {
        DateTime startTime = DateTime.now(); // Adjusting start time by 5 minutes for clock skew
        DateTime expiry = startTime.add(Duration(hours: expiryHours));
        String formattedStartTime = DateFormat("yyyy-MM-ddTHH:mm:ss'Z'").format(startTime);
        String formattedExpiry = DateFormat("yyyy-MM-ddTHH:mm:ss'Z'").format(expiry);
    
        String stringToSign = 'sp=$permissions\nst=$formattedStartTime\nse=$formattedExpiry\nspr=https\nsv=2022-11-02\nsr=$sr\n$resourceUri'; // Include sr parameter
        String signature = _generateSignature(stringToSign, key);
    
        return 'sp=$permissions&st=$formattedStartTime&se=$formattedExpiry&spr=https&sv=2022-11-02&sr=$sr&sig=$signature'; // Include sr parameter
      }
    
      String _generateSignature(String input, String key) {
        var keyBytes = utf8.encode(key);
        var inputBytes = utf8.encode(input);
        var hmacSha256 = Hmac(sha256, keyBytes);
        var digest = hmacSha256.convert(inputBytes);
        return Uri.encodeComponent(base64.encode(digest.bytes));
      }
    }
    
    void main() {
      String resourceUri = "https://account_name.blob.core.windows.net/containerName/example.txt";
      String key = "accountkey";
      String permissions = "r"; // r for read, w for write, d for delete, etc.
      String sr = "b"; // Specify the resource type: b for Blob service, c for Container service, etc.
      int expiryHours = 24; // Expiry duration in hours
    
      SasTokenGenerator generator = SasTokenGenerator();
      String sasToken = generator.generateSasToken(
        resourceUri: resourceUri,
        key: key,
        permissions: permissions,
        sr: sr, // Pass sr parameter
        expiryHours: expiryHours,
      );
    
      print('Generated SAS Token: $sasToken');
    }
    

    Output: enter image description here