C# 用户委托SAS令牌

C# 用户委托SAS令牌,c#,authentication,asp.net-core,azure-storage,C#,Authentication,Asp.net Core,Azure Storage,我正在使用.NETCore3.0 我正在尝试创建一个守护程序应用程序,它读取和写入存储blob容器中的文件。我想使用用户委托的SAS令牌,因为这似乎是最佳实践 我试着按照房间里的指示去做,但遇到了麻烦。我相信代码应该写出用户委派键的一些属性,但在我的例子中,它什么都不做 我用自己的帐户登录到浏览器google Chrome上,该浏览器拥有订阅的所有者角色。 我怀疑身份验证过程不正确,并尝试了一些方法,例如为应用程序分配角色,然后使用TokenCredential而不是DefaultAzureCr

我正在使用.NETCore3.0

我正在尝试创建一个守护程序应用程序,它读取和写入存储blob容器中的文件。我想使用用户委托的SAS令牌,因为这似乎是最佳实践

我试着按照房间里的指示去做,但遇到了麻烦。我相信代码应该写出用户委派键的一些属性,但在我的例子中,它什么都不做

我用自己的帐户登录到浏览器google Chrome上,该浏览器拥有订阅的所有者角色。 我怀疑身份验证过程不正确,并尝试了一些方法,例如为应用程序分配角色,然后使用TokenCredential而不是DefaultAzureCredential,但没有任何更改

这是实际代码。我复制并粘贴了示例代码,刚刚添加了wait blobClient.GetPropertiesAsync以进行调试。 代码的结果正好在GetPropertiesAsync之前,没有错误

using System;
using System.IO;
using System.Threading.Tasks;
using Azure;
using Azure.Identity;
using Azure.Storage.Sas;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;

namespace TestUserDelegatedSAS
{
    class Program
    {
        static void Main(string[] args)
        {
            String accountName = "deleted";
            String containerName = "deleted";
            String blobName = "deleted.txt";
            GetUserDelegationSasBlob(accountName, containerName, blobName).GetAwaiter();

        }

        async static Task<Uri> GetUserDelegationSasBlob(string accountName, string containerName, string blobName)
        {
            // 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());

            Console.WriteLine("before GetPropertiesAsync()");
            await blobClient.GetPropertiesAsync();
            Console.WriteLine("after GetPropertiesAsync()");

            // 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));

            // Read the key's properties.
            Console.WriteLine("User delegation key properties:");
            Console.WriteLine("Key signed start: {0}", key.SignedStartsOn);
            Console.WriteLine("Key signed expiry: {0}", key.SignedExpiresOn);
            Console.WriteLine("Key signed object ID: {0}", key.SignedObjectId);
            Console.WriteLine("Key signed tenant ID: {0}", key.SignedTenantId);
            Console.WriteLine("Key signed service: {0}", key.SignedService);
            Console.WriteLine("Key signed version: {0}", key.SignedVersion);
            Console.WriteLine();

            // 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
            };

            Console.WriteLine("User delegation SAS URI: {0}", fullUri);
            Console.WriteLine();
            return fullUri.Uri;
        }

        private static async Task ReadBlobWithSasAsync(Uri sasUri)
        {
            // Try performing blob operations using the SAS provided.

            // Create a blob client object for blob operations.
            BlobClient blobClient = new BlobClient(sasUri, null);

            // Download and read the contents of the blob.
            try
            {
                // Download blob contents to a stream and read the stream.
                BlobDownloadInfo blobDownloadInfo = await blobClient.DownloadAsync();
                using (StreamReader reader = new StreamReader(blobDownloadInfo.Content, true))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        Console.WriteLine(line);
                    }
                }

                Console.WriteLine();
                Console.WriteLine("Read operation succeeded for SAS {0}", sasUri);
                Console.WriteLine();
            }
            catch (RequestFailedException e)
            {
                // Check for a 403 (Forbidden) error. If the SAS is invalid,
                // Azure Storage returns this error.
                if (e.Status == 403)
                {
                    Console.WriteLine("Read operation failed for SAS {0}", sasUri);
                    Console.WriteLine("Additional error information: " + e.Message);
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine(e.Message);
                    Console.ReadLine();
                    throw;
                }
            }
        }

    }

}
我真的被困在这里了,任何建议都非常感谢。
感谢您的帮助。

根据我的研究,如果您想请求用户委派密钥,必须为安全主体分配Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey操作。同时,以下内置RBAC角色包括Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey操作。有关更多详细信息,请参阅

贡献者

存储帐户贡献者

存储Blob数据贡献器

存储Blob数据所有者

存储Blob数据读取器

存储Blob委托器

此外,请注意,如果您使用Storage Blob Data Contributor、Storage Blob Data Owner、, 存储Blob数据读取器和 存储Blob Delegator,我们无法使用这些角色获取帐户属性。因为这些角色没有权限在帐户级别执行操作。换句话说,我们不能调用方法BlobServiceClient.GetPropertiesAsync。有关更多详情,请参阅官方网站

具体步骤如下

创建服务主体
根据我的研究,如果要请求用户委派密钥,必须为安全主体分配Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey操作。同时,以下内置RBAC角色包括Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey操作。有关更多详细信息,请参阅

贡献者

存储帐户贡献者

存储Blob数据贡献器

存储Blob数据所有者

存储Blob数据读取器

存储Blob委托器

此外,请注意,如果您使用Storage Blob Data Contributor、Storage Blob Data Owner、, 存储Blob数据读取器和 存储Blob Delegator,我们无法使用这些角色获取帐户属性。因为这些角色没有权限在帐户级别执行操作。换句话说,我们不能调用方法BlobServiceClient.GetPropertiesAsync。有关更多详情,请参阅官方网站

具体步骤如下

创建服务主体
我已将身份验证部分更改为BlobServiceClient blobClient=new BlobServiceClientnew UriblobEndpoint,new InteractiveBrowserCredential;成功了!我还是不明白为什么。任何一条建议都会有很大的帮助。DefaultAzureCredential您是否可以使用您的MSI,请检查您的MSI是否具有足够的权限?我在笔记本电脑上测试了此代码,因此肯定没有可用的MSI。我会在虚拟机上测试这个,然后回复你。你还有其他问题吗?如果您没有其他问题,可以吗?如果您正在编写非交互式守护程序,为什么要使用委托用户访问?使用托管标识是否更有意义?或者,您是否需要仅在上游某个位置的用户授予特定访问权限时才为守护进程分配特定访问权限?否则,我认为您应该使用托管标识并授予守护进程必要的权限。当MIS不起作用时,是本地的吗?您是否使用az login对存储帐户进行了必要的权限验证?我已将验证部分更改为BlobServiceClient blobClient=new BlobServiceClient new UriblobEndpoint,new InteractiveBrowserCredential;成功了!我还是不明白为什么。任何一条建议都会有很大的帮助。DefaultAzureCredential您是否可以使用您的MSI,请检查您的MSI是否具有足够的权限?我在笔记本电脑上测试了此代码,因此肯定没有可用的MSI。我会在虚拟机上测试这个,然后回复你。你还有其他问题吗?如果您没有其他问题,可以吗?如果您正在编写非交互式守护程序,为什么要使用委托用户访问?使用托管标识是否更有意义?或者,您是否需要仅在用户som授予特定访问权限时才将特定访问权限分配给守护进程
上游在哪里?否则,我认为您应该使用托管标识并授予守护进程必要的权限。当MIS不起作用时,是本地的吗?您是否使用az登录来验证存储帐户的必要权限?谢谢您的评论。我重新检查了分配的角色,我的用户ID中有服务管理员,服务管理员应该包括所有必要的角色。如果我错了,请纠正我。另一方面,我的应用程序没有帐户级别的角色,因此这解释了BlobServiceClient.GetPropertiesAsync失败的原因。再次感谢您的宝贵意见。感谢您的评论。我重新检查了分配的角色,我的用户ID中有服务管理员,服务管理员应该包括所有必要的角色。如果我错了,请纠正我。另一方面,我的应用程序没有帐户级别的角色,因此这解释了BlobServiceClient.GetPropertiesAsync失败的原因。再次感谢您的宝贵意见。
az ad sp create-for-rbac --name ServicePrincipalName \
    --role "Storage Blob Data Reader" \
--scope 

</subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>  
var delegationKey = await blobServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(7));
        BlobSasBuilder sasBuilder = new BlobSasBuilder()
        {
            BlobContainerName = containerName,
            BlobName = blobName,
            Resource = "b",
            StartsOn = DateTimeOffset.UtcNow,
            ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
        };
        sasBuilder.SetPermissions(BlobSasPermissions.Read);
        Console.WriteLine(sasBuilder.Permissions);
        var sasQueryParams = sasBuilder.ToSasQueryParameters(delegationKey, storageProviderSettings.AccountName).ToString();
        UriBuilder sasUri = new UriBuilder()
        {
            Scheme = "https",
            Host = string.Format("{0}.blob.core.windows.net", storageProviderSettings.AccountName),
            Path = string.Format("{0}/{1}", containerName, blobName),
            Query = sasQueryParams
        };