如何使用 SAS 令牌从 C# 连接到 Azure BlobStorage?

Posted

技术标签:

【中文标题】如何使用 SAS 令牌从 C# 连接到 Azure BlobStorage?【英文标题】:How to use SAS Token to connect to Azure BlobStorage from C#? 【发布时间】:2022-01-03 05:49:33 【问题描述】:

tl;dr: 我正在尝试使用 SAS 从 C# 连接到 Azure BlobStorage,但似乎无法通过 StorageException 说“服务器无法验证请求。 "我怀疑我的连接字符串有问题。


我正在使用库 Microsoft.Azure.Storage.Blob11.2.3.0 和 Microsoft.Azure.Storage.Common11.2.3.0 从 .NET Core 3.1 应用程序连接到 Azure BlobStorage。

我建立此连接的 C# 代码如下:

var storageAccount = CloudStorageAccount.Parse(connectionString);
var blobClient = storageAccount.CreateCloudBlobClient();

当使用包含字段AccountNameAccountKeyEndpointSuffixDefaultEndpointsProtocol(这是https1 的连接字符串时,它可以完美运行。 (我可以连接并执行诸如枚举容器和 blob 之类的操作,还可以创建容器和 blob 并上传数据。)


现在,我应该使用 SAS 连接到同一个 BlobStorage。为此,我得到了以下信息(这里匿名为某种“占位符”,因为我将在下面引用它们):

<StorageAccount>(与上述连接字符串中AccountName字段的值相同) <Container> <Blob-SAS-Token> <Blob-SAS-URL>(这实际上是由此处找到的其他信息组成,即<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>/<Container>?<Blob-SAS-Token>

如上所述,我可以使用<Blob-SAS-URL> 成功地从Microsoft Azure 存储资源管理器 建立与上述 BlobStorage 容器的连接。2

但是,到目前为止,我无法从我的 C# 代码中成功使用 SAS。

我尝试了各种方法来编写我的连接字符串,例如:

BlobEndpoint=<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>;SharedAccessSignature=<Blob-SAS-Token> BlobEndpoint=<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>/<Container>;SharedAccessSignature=<Blob-SAS-Token>

根据docs,这应该工作。在那里,一个基于 SAS 的连接字符串被概述为包含最多五个字段 - BlobEndpointQueueEndpointTableEndpointFileEndpointSharedAccessSignature - 其中只有(任何)四个端点之一 必须在 SAS 旁边指定。

我还尝试过创建/填充CloudStorageAccount 实例,而不是通过(可能格式错误的)连接字符串,例如:

var storageAccount = new CloudStorageAccount(
    new StorageCredentials("<Blob-SAS-Token>"),
    "<StorageAccount>", "<EndpointSuffix>", true);

不幸的是,无论我尝试什么,只要我尝试以这种方式从 BlobStorage 检索任何数据,就会抛出 Microsoft.Azure.Storage.StorageException,声明

服务器未能验证请求。确保 Authorization 标头的值格式正确,包括签名。

我本地机器上的 UTC 时间与我可以在在线资源上找到的当前 UTC 时间完全匹配。因为我可以从同一台机器上的另一个应用程序连接我的 SAS 信息,所以问题很可能与环境的任何方面无关(例如在某些阻止列表或类似列表中缺少我的 IP 地址条目),无论如何。相反,我怀疑我没有提供足够的信息来建立连接。

我必须进行哪些更改才能使此连接正常工作?


1:我将在写这篇文章时为各种标识符和凭据使用某种“占位符”,以免泄露任何机密信息。我希望这不会太混乱。另一方面,它实际上应该允许通过几个查找和替换操作轻松地将信息调整到可用的样本端点。

2:为此,我右键单击 Storage Accounts 树节点,然后连接到 Azure 存储... > Blob 容器 > SAS URL(共享访问签名

【问题讨论】:

这里有一个类似的问题你可以参考***.com/questions/70097124/… @SwethaKandikonda-MT:这确实很有帮助,谢谢。你可以添加一个答案吗?对我来说,这里的关键点是,当使用(特定于容器的)SAS 时,我不能只使用与整个存储帐户的连接字符串相同的代码来连接到 BlobStorage。也就是说,没有办法将 SAS 和目标容器放入连接字符串并将其提供给CloudStorageAccount.Parse(或者有吗?)。 【参考方案1】:

以下基于连接字符串的解决方案。

基于Swetha's comment,我能够使用以下代码进行连接:

var creds = new StorageCredentials("<Blob-SAS-Token>");
var blobContainer = new CloudBlobContainer(new Uri("<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>/<Container>"), creds);

然后我可以从blobContainer 检索和上传数据。

不幸的是,这意味着连接到 BlobStorage 的代码看起来与连接字符串不同。因此,我需要提供、测试和维护两个不同的代码路径,具体取决于提供了哪种连接配置(并且不能保证第三种身份验证方法不需要另一个代码路径 - 我现在有 @ 987654322@).


更新:基于an answer to my question about storing connection data,我现在了解到实际上可以使用连接字符串与 SAS 连接。以下格式已被证明有效:

BlobEndpoint=&lt;DefaultEndpointsProtocol&gt;://&lt;StorageAccount&gt;.blob.&lt;EndpointSuffix&gt;;SharedAccessSignature=&lt;Blob-SAS-Token&gt; DefaultEndpointsProtocol=&lt;DefaultEndpointsProtocol&gt;;EndpointsSuffix=&lt;EndpointsSuffix&gt;;SharedAccessSignature=&lt;Blob-SAS-Token&gt;

然后,重要的一点是(至少如果 SAS 是特定于容器的,就像我得到的那样 - 我不确定是否总是这样)我可以在容器中工作 ,但不是 on 容器(或容器之外的任何东西)。那就是:

虽然我可以通过将容器名称传递给GetContainerReference 来检索CloudBlobContainer 实例,但我不能调用ListContainers(这会引发异常,而不是仅枚举我可以通过SAS 访问的容器集)。 我必须假设容器已经存在。 Exists()CreateIfNotExists() 在容器上调用时都会抛出异常。1

一旦遵守这些限制,就可以再次使用CloudStorageAccount.Parse(connectionString)


1:我创建了一个separate question about how to safely check for a container's existence。

【讨论】:

以上是关于如何使用 SAS 令牌从 C# 连接到 Azure BlobStorage?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中使用服务主体(clientId 和 clientSecret)为 Azure Data Lake Store(Gen-2)创建 SAS 令牌?

我们可以在不使用 SAS 令牌的情况下通过 c# 代码调用 Azure API 管理吗

C# 使用 REST API 连接到 Azure 媒体服务帐户

如何在 Java 中基于 SAS 令牌访问 Azure WASB 容器?

使用 SAS 令牌从 Azure 阶段读取时出现雪花错误

Azure IoT 中心 SAS 令牌不会过期