如何使用最新的 Azure SDK .NET API v12 在 Blob 上获取共享访问签名?
Posted
技术标签:
【中文标题】如何使用最新的 Azure SDK .NET API v12 在 Blob 上获取共享访问签名?【英文标题】:How to get a Shared Access Signature on a Blob using the latest Azure SDK .NET API v12? 【发布时间】:2020-03-25 20:26:12 【问题描述】:我曾经能够使用 v11 Azure SDK API 在 Blob 上创建共享访问签名,如下所示:
var containerName = "mycontainer";
var blobName = "myblob";
CloudStorageAccount storageAccount
= CloudStorageAccount.Parse(<StorageConnectionString>);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
SharedAccessBlobPermissions permission = SharedAccessBlobPermissions.Read;
TimeSpan clockSkew = TimeSpan.FromMinutes(15d);
TimeSpan accessDuration = TimeSpan.FromMinutes(15d);
var blobSAS = new SharedAccessBlobPolicy
SharedAccessStartTime = DateTime.UtcNow.Subtract(clockSkew),
SharedAccessExpiryTime = DateTime.UtcNow.Add(accessDuration) + clockSkew,
Permissions = permissions
;
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
string sasBlobToken = blob.GetSharedAccessSignature(blobSAS);
...
我想使用最新的 v12 .NET API,它似乎将 CloudBlobClient
替换为 BlobServiceClient
、CloudBlobContainer
替换为 BlobContainerClient
和 CloudBlockBlob
替换为 BlobClient
。
但是CloudBlockBlob
实例上可用的方法GetSharedAccessSignature
在BlobClient
实例上不可用。
问题
如何使用最新的 Azure SDK .NET API v12 从BlobClient
实例获取共享访问签名?
【问题讨论】:
【参考方案1】:Sajeetharan 的回答让我寻找一个实际存在的 BlobSasBuilder 类。
这是我如何在服务器上构建一个:
// Creates a client to the BlobService using the connection string.
var blobServiceClient = new BlobServiceClient(storageConnectionString);
// Gets a reference to the container.
var blobContainerClient = blobServiceClient.GetBlobContainerClient(<ContainerName>);
// Gets a reference to the blob in the container
BlobClient blobClient = containerClient.GetBlobClient(<BlobName>);
// Defines the resource being accessed and for how long the access is allowed.
var blobSasBuilder = new BlobSasBuilder
StartsOn = DateTime.UtcNow.Subtract(clockSkew),
ExpiresOn = DateTime.UtcNow.Add(accessDuration) + clockSkew,
BlobContainerName = <ContainerName>,
BlobName = <BlobName>,
;
// Defines the type of permission.
blobSasBuilder.SetPermissions(BlobSasPermissions.Write);
// Builds an instance of StorageSharedKeyCredential
var storageSharedKeyCredential = new StorageSharedKeyCredential(<AccountName>, <AccountKey>);
// Builds the Sas URI.
BlobSasQueryParameters sasQueryParameters = blobSasBuilder.ToSasQueryParameters(storageSharedKeyCredential);
这里是如何在客户端使用它:
// Builds the URI to the blob storage.
UriBuilder fullUri = new UriBuilder()
Scheme = "https",
Host = string.Format("0.blob.core.windows.net", <AccountName>),
Path = string.Format("0/1", <ContainerName>, <BlobName>),
Query = sasQueryParameters.ToString()
;
// Get an instance of BlobClient using the URI.
var blobClient = new BlobClient(fullUri.Uri, null);
// Upload stuff in the blob.
await blobClient.UploadAsync(stream);
附录
正如@one2012 在 cmets 中提到的,a page has been put up few months later 在此答案之后展示了 Azure.Storage 命名空间中的所有功能。该链接可用于获取更多信息。
更新
在服务器端,我有一个 Azure 函数,它现在将 Azure 存储与函数的托管标识连接起来。当我连接存储时,我不再使用帐户,只使用存储的端点:
BlobContainerClient blobContainerClient = new(new Uri(containerEndpoint), new DefaultAzureCredential());
这使得初始服务器代码的以下部分有点棘手,因为我曾经使用CloudStorageAccount.Credentials.GetExportKeys()
方法来获取帐户的密钥。使用托管身份时,我似乎无法再访问它了:
// Builds an instance of StorageSharedKeyCredential
var storageSharedKeyCredential = new StorageSharedKeyCredential(<AccountName>, <AccountKey>);
事实证明我必须使用 User Delegation 来构建 SAS Uri:
...
BlobServiceClient blobServiceClient = blobClient.GetParentBlobContainerClient().GetParentBlobServiceClient();
UserDelegationKey userDelegationKey = await blobServiceClient.GetUserDelegationKeyAsync
(
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddMinutes(5d)
);
BlobUriBuilder blobUriBuilder = new (blobClient.Uri)
// Specify the user delegation key.
Sas = blobSasBuilder.ToSasQueryParameters(userDelegationKey, blobServiceClient.AccountName)
;
string uri = blobUriBuilder.ToUri();
【讨论】:
我找不到从连接字符串而不是使用 AccountName 和 AccountKey 获取 storageSharedKeyCredential 的方法。你知道吗? @benjaminvar csBuilder = new DbConnectionStringBuilder(); csBuilder.ConnectionString = _configuration.GetConnectionString("MyCS"); var storageSharedKeyCredential = new StorageSharedKeyCredential( (string)csBuilder["AccountName"], (string)csBuilder["AccountKey"]);
如果你要迁移到 Azure.Storage 命名空间,这个页面是我发现的最有用的东西craftedforeveryone.com/…
您,先生,救了我的命和我的心理健康
我花了一段时间才发现我的 SDK 已经过时了。此版本或更高版本支持此答案中的所有功能:经过大量搜索,我找到了一些关于此的 Microsoft 文档:https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-dotnet
此详细信息使用用户委托密钥生成 SAS 而不是帐户密钥,但更改只是对 .ToSasQueryParameters() 的不同重载,如其他答案中所述。
文章中的一些关键 sn-ps 可以将其连接起来。首先创建你的 BlobServiceClient:
// Construct the blob endpoint from the account name.
string blobEndpoint = string.Format("https://0.blob.core.windows.net", accountName);
// Create a new Blob service client with Azure AD credentials.
BlobServiceClient blobClient = new BlobServiceClient(new Uri(blobEndpoint),
new DefaultAzureCredential());
获取用户委托密钥,这将用于生成 SAS:
// Get a user delegation key for the Blob service that's valid for seven days.
// You can use the key to generate any number of shared access signatures over the lifetime of the key.
UserDelegationKey key = await blobClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddDays(7));
最后创建 SAS URI:
// Create a SAS token that's valid for one hour.
BlobSasBuilder sasBuilder = new BlobSasBuilder()
BlobContainerName = containerName,
BlobName = blobName,
Resource = "b",
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
;
// Specify read permissions for the SAS.
sasBuilder.SetPermissions(BlobSasPermissions.Read);
// Use the key to get the SAS token.
string sasToken = sasBuilder.ToSasQueryParameters(key, accountName).ToString();
// Construct the full URI, including the SAS token.
UriBuilder fullUri = new UriBuilder()
Scheme = "https",
Host = string.Format("0.blob.core.windows.net", accountName),
Path = string.Format("0/1", containerName, blobName),
Query = sasToken
;
【讨论】:
【参考方案3】:使用适用于 .NET 的 Azure Blob 存储客户端库 v12:
BlobSasBuilder blobSasBuilder = new BlobSasBuilder()
BlobContainerName = blobContainerName,
BlobName = blobName,
Resource = "b", //b = blob, c = container
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(lifetimeMinutes)
;
blobSasBuilder.SetPermissions(BlobSasPermissions.Read);
StorageSharedKeyCredential storageSharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
string sas = blobSasBuilder.ToSasQueryParameters(storageSharedKeyCredential).ToString();
如果必须根据分配给容器的访问策略生成共享访问签名(SAS 令牌),请使用以下方法
BlobSasBuilder blobSasBuilder = new BlobSasBuilder()
BlobContainerName = blobContainerName,
BlobName = blobName,
Resource = "b", //b = blob, c = container
Identifier = "ReadOnlyPolicy" //string value referees to the access policy created and assigned to the container.
;
StorageSharedKeyCredential storageSharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
string sas = blobSasBuilder.ToSasQueryParameters(storageSharedKeyCredential).ToString();
注意:当 SAS 令牌生成基于分配给容器的访问策略时,您将无法在 BlobSasBuilder 中定义权限、开始时间或结束时间。您将收到运行时异常,因为“访问策略字段可以与签名或 SAS 标识符相关联,但不能同时与两者相关联”
参考:https://www.craftedforeveryone.com/beginners-guide-and-reference-to-azure-blob-storage-sdk-v12-dot-net-csharp/
https://www.craftedforeveryone.com/beginners-guide-and-reference-to-azure-blob-storage-sdk-v12-dot-net-csharp/#generate_access_policy_based_sas_token_for_a_blob
【讨论】:
【参考方案4】:在此处:https://docs.microsoft.com/en-us/rest/api/storageservices/delegate-access-with-shared-access-signature 表示 Azure 存储支持三种不同类型的共享访问签名 (SAS):
-
帐户级别 SAS,这是您在 v11 SDK 中使用的。详细信息和示例:https://docs.microsoft.com/en-us/azure/storage/common/storage-account-sas-create-dotnet
服务级别 SAS,使用 v12 (& V11) SDK。详细信息和示例:https://docs.microsoft.com/en-us/azure/storage/blobs/sas-service-create?tabs=dotnet
用户委托 SAS,这是 Microsoft 推荐的方法,前提是您可以使用 Azure Active Directory 用户使用 v12 SDK 进行签名。详细信息和示例:https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-dotnet
1 和 2 都使用帐户的共享密钥来生成 SAS 令牌,而 3 使用从 AAD 帐户用户生成的密钥,因此在需要时(理论上)更安全且更易于撤销目标。见https://docs.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas#:~:text=Authorization%20of%20a%20user%20delegation%20SAS,-When%20a%20client&text=This%20approach%20provides%20an%20additional,is%20a%20security%20best%20practice。有关为什么这样更安全的更多详细信息(“这种方法提供了额外的安全级别,并且避免了将帐户访问密钥与应用程序代码一起存储的需要。出于这些原因,使用 Azure 创建 SAS AD 凭据是一种安全最佳实践。”)
现在存储帐户都支持使用,但我得到的印象是v12 SDK中实施不支持帐户级别(我是推测 - 所以不要引用我,但我也找不到这个)或者有其他隐藏的方法可以做到这一点(当然 BlobSasBuilder.ToSasQueryParameters() 方法只有两个重载),我猜这会让用户委派或服务级别的方法是您现在打算实现的。
【讨论】:
【参考方案5】:使用适用于 .NET 的 Azure Blob 存储客户端库 v12:
BlobSasBuilder blobSasBuilder = new BlobSasBuilder()
BlobContainerName = blobContainerName,
BlobName = blobName,
Resource = "b", //b = blob, c = container
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(lifetimeMinutes)
;
blobSasBuilder.SetPermissions(BlobSasPermissions.Read);
StorageSharedKeyCredential storageSharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
string sas = blobSasBuilder.ToSasQueryParameters(storageSharedKeyCredential).ToString();
【讨论】:
【参考方案6】:private string BuildSASUri(BlobClient blob)
// Create a user SAS that only allows reading for a minute
BlobSasBuilder sas = new BlobSasBuilder
BlobContainerName = blob.BlobContainerName,
BlobName = blob.Name,
Resource = "b",
ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(1)
;
// Allow read access
sas.SetPermissions(BlobSasPermissions.Read);
var storageSharedKeyCredential = new StorageSharedKeyCredential(
_iconfiguration.GetValue<string>("StorageAccount:AccountName"),
_iconfiguration.GetValue<string>("StorageAccount:AccountKey")
);
return sas.ToSasQueryParameters(storageSharedKeyCredential).ToString();
以上是我的工作代码。
但是,我不知道如何使用 V12 创建存储访问策略。应该是这样的:https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.blobcontainerclient.setaccesspolicy?view=azure-dotnet
但我认为微软完全忘记了提供一种创建 BlobSignedIdentifier 的方法。
文档已过期:https://docs.microsoft.com/en-us/azure/storage/common/storage-stored-access-policy-define-dotnet?toc=%2fazure%2fstorage%2fblobs%2ftoc.json
其中使用了 Microsoft.Azure.Storage.Blob,但 https://www.nuget.org/packages/Microsoft.Azure.Storage.Blob/ 说不要再使用它了。
【讨论】:
以上是关于如何使用最新的 Azure SDK .NET API v12 在 Blob 上获取共享访问签名?的主要内容,如果未能解决你的问题,请参考以下文章
使用 .NET SDK 获取 Azure Blob 存储区域?
Azure 存储:如何使用 .NET SDK 生成 SAS 连接字符串
如何使用代理从 Cosmos SDK .Net 连接到 Azure Cosmos?
如何使用 .NET v12 SDK 在 Azure Blob 存储中上传具有指定 ContentType 的 Blob?