使用 Azure.Storage.Blobs 通过 .NET Core 3.1 生成 SAS 到期令牌

Posted

技术标签:

【中文标题】使用 Azure.Storage.Blobs 通过 .NET Core 3.1 生成 SAS 到期令牌【英文标题】:Using Azure.Storage.Blobs to generate SAS expiring tokens with .NET Core 3.1 【发布时间】:2020-10-30 05:26:51 【问题描述】:

这个有点麻烦。在遵循 Microsoft 文档中的示例后,我得到了一个 SAS 令牌,但我遇到了 SAS 令牌未通过身份验证的问题。

string sastoken = "";
            BlobServiceClient blobServiceClient = new BlobServiceClient("DefaultEndpointsProtocol=https;AccountName=accountname;AccountKey=accountkey;EndpointSuffix=core.windows.net");
            string containerName = containername;
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
            BlobSasBuilder sasBuilder = new BlobSasBuilder()
            
                ExpiresOn = DateTime.UtcNow + (new TimeSpan(24, 0, 0)),
                BlobContainerName = containerName,
                BlobName = imageData.filename,
                Resource = "b"
            ;

            sasBuilder.SetPermissions(BlobSasPermissions.Read);
            sastoken = sasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(containername, credentialkey)).ToString();

            UriBuilder fulluri = new UriBuilder()
            
                Scheme = "https",
                Host = string.Format("0.blob.core.windows.net", containername),
                Path = string.Format("0/1", "blobtest", "file.bmp"),
                Query = sastoken
            ;

            imageData.url = fulluri.Uri.ToString();

imageData.url 返回为:https://accountname.blob.core.windows.net/containername/file.bmp?sv=2019-07-07&se=2020-07-10T14%3A54%3A43Z&sr=b&sp=r&sig=UXvC7SAXqQtsVgfXj6L%2BOIinTMhQj%2F3NH95v%2FLRvM8g%3D

我收到一个身份验证错误,但 SAS 令牌的全部意义在于提供该身份验证。我确定我在这里遗漏了一些东西,但没有发现我犯了错误的任何地方。我找到的大部分信息都与 Microsoft.Azure.Storage 包有关,而不是与 Azure.Storage.Blob 命名空间有关。欢迎任何帮助或建议。 谢谢!

【问题讨论】:

这可能是由于处理您的请求的服务器和客户端之间的时间差。尝试将sasBuilder.StartsOn 属性设置为更早的时间,看看是否有帮助。类似于:sasBuilder.StartsOn = DateTime.UtcNow - TimeSpan.FromMinutes(5). 我已经尝试过了,在两个方向都使用了 24 小时缓冲。不幸的是,结果是一样的。 您能否确认 blob 容器名称和 blob 名称与您在创建 URL 时使用的名称相同。否则你的代码在我看来没问题。 看起来您为 image.filename 生成了 SAS 令牌,但您的 URL 始终使用静态 blobtestfile.bmp。你想改变那些以使用动态值并尝试这种方式吗? 是的,请求和生成的 url 之间的容器和 blob 名称是正确的。根据我的 Azure 存储帐户和 blob,它们也是正确的。 【参考方案1】:

我使用类似的东西,使用Microsoft.WindowsAzure.Storage nuget 包:

private Uri GetSasForBlob(CloudBlob blob, DateTime expiry, SharedAccessBlobPermissions permissions = SharedAccessBlobPermissions.None)

    var offset = TimeSpan.FromMinutes(10);
    var policy = new SharedAccessBlobPolicy
    
        SharedAccessStartTime = DateTime.UtcNow.Subtract(offset),
        SharedAccessExpiryTime = expiry.Add(offset),
                Permissions = permissions
    ;
#pragma warning disable CA5377 // Use Container Level Access Policy
    var sas = blob.GetSharedAccessSignature(policy);
#pragma warning restore CA5377 // Use Container Level Access Policy
    return new Uri($"blob.Urisas");


使用Azure.Storage.Blobs更新:

// Read these from config:
// var accountName = "accountname";
// var accountKey = "xxxxxxx";
// var blobServiceEndpoint = $"https://accountName.blob.core.windows.net";


private Uri GetSasForBlob(string blobname, string containerName, DateTime expiry, BlobAccountSasPermissions permissions = BlobAccountSasPermissions.Read)

    var offset = TimeSpan.FromMinutes(10);

    var credential = new StorageSharedKeyCredential(accountName, accountKey);
    var sas = new BlobSasBuilder
    
        BlobName = blobname,
        BlobContainerName = containerName,
        StartsOn = DateTime.UtcNow.Subtract(offset),
        ExpiresOn = expiry.Add(offset)
    ;
    sas.SetPermissions(permissions);

    UriBuilder sasUri = new UriBuilder($"blobServiceEndpoint/containerName/blobname");
    sasUri.Query = sas.ToSasQueryParameters(credential).ToString();

    return sasUri.Uri;

参考:https://github.com/Azure/azure-sdk-for-net/blob/42839e7dea6be316024f168ecd08f3134bc57a47/sdk/storage/Azure.Storage.Blobs/samples/Sample02_Auth.cs#L137

【讨论】:

这是使用 Microsoft.Azure.Storage,已被 Azure.Storage.Blobs 取代 您答案中的代码使用的是旧版 SDK,而 OP 使用的是新版 SDK。 您能否详细说明生成文字标记而不是 URI? @Vivere sas.ToSasQueryParameters(credential).ToString() 生成 SAS 签名。尽管您几乎总是需要 URL。如果您询问如何从Uri 中获取字符串文字,您可以使用uri.AbsoluteUri【参考方案2】:

您生成的 SAS 令牌和 URL 似乎使用不同的帐户名称、容器名称和 blob 名称值。 考虑更新 URL 生成代码以使用相同的值。

UriBuilder fulluri = new UriBuilder()

  Scheme = "https",
  Host = string.Format("0.blob.core.windows.net", accountname),
  Path = string.Format("0/1", containerName, imageData.fileName),
  Query = sastoken
;

希望这会有所帮助。

【讨论】:

以上是关于使用 Azure.Storage.Blobs 通过 .NET Core 3.1 生成 SAS 到期令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Azure.Storage.Blobs 程序集对 Azure Blob 存储操作设置重试策略?

如何使用 C# 中的 Azure.Storage.Blobs 从 Azure 存储 Blob 以 ByteArray 格式获取文件

Azure SAS 令牌不适用于 Azure.Storage.Blobs BlobServiceClient

如何从 Azure.Storage.Blobs 模拟 GetBlobsByHierarchy()?

VS2015 无法安装包 Azure.Storage.Blobs.12.5.1

无法使用 Azure.Storage.Blobs NuGet 包将文件上传到 Azure Blob 存储