0

我们在使用 GetUserDelegationKey 生成 SAS 令牌时遇到异常,这是我们在并发请求中遇到的异常。

System.ObjectDisposedException: Cannot access a closed Stream.
   at System.IO.MemoryStream.Write(ReadOnlySpan`1 buffer)
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Dispose(Boolean disposing)
   at System.Xml.XmlTextWriter.Close()
   at Azure.Core.XmlWriterContent.Dispose()
   at Azure.Core.Pipeline.HttpClientTransport.PipelineRequest.Dispose()
   at Azure.Core.HttpMessage.Dispose()
   at Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey(KeyInfo keyInfo, Nullable`1 timeout, CancellationToken cancellationToken)
   at Azure.Storage.Blobs.BlobServiceClient.GetUserDelegationKeyInternal(Nullable`1 startsOn, DateTimeOffset expiresOn, Boolean async, CancellationToken cancellationToken)
   at Azure.Storage.Blobs.BlobServiceClient.GetUserDelegationKey(Nullable`1 startsOn, DateTimeOffset expiresOn, CancellationToken cancellationToken)
   at service.mediastorage.DefsultCredntialStorageService.GetUrlWithAccessToken(String url, Double expiredInHours)
   at service.services.VideoService.Convert(Video video) in /home/vsts/work/Source/service.services/VideoService.cs:line 456
   at System.Linq.Enumerable.SelectListIterator`2.ToList()
   at service.services.VideoService.GetVideosByPaginationaAsync(VideoFilterQueryParams filterParameters, LoggedInUserInfo loggedInUserInfo) in /home/vsts/work/Source/service.services/VideoService.cs:line 175
   at service.api.Controllers.VideoController.GetVideosByPaginationAsync(VideoFilterQueryParams videoFilterQueryParameters) in /home/vsts/work/Source/service.api/Controllers/VideoController.cs:line 216

以下代码用于生成 sastoken

        public  string GetUrlWithAccessToken(string url, double expiredInHours = 0)
        {
            if (string.IsNullOrEmpty(url)) return null;
            var uri = new Uri(url);

            var blobClient = new BlobClient(uri, GetDefaultCredentials());
            var blobServiceClient = GetBlobServiceClient(_amsSettings.StorageEndPointUrl);

            UserDelegationKey userDelegationKey =  blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow,
                                                                               DateTimeOffset.UtcNow.AddHours(1));
            string sasTokenUrl = GetBlobUrlWithAccessToken(userDelegationKey, blobClient, url, expiredInHours);
            return sasTokenUrl;
        }
        
         private string GetBlobUrlWithAccessToken(UserDelegationKey userDelegationKey, BlobClient blobClient,string url,double expiredInHours)
        {
            // Create a SAS token
            BlobSasBuilder sasBuilder = new BlobSasBuilder()
            {
                BlobContainerName = blobClient.GetParentBlobContainerClient().Name,
                BlobName = blobClient.Name,
                Resource = "b"
            };

          
            sasBuilder.ExpiresOn = DateTimeOffset.UtcNow.AddHours(expiredInHours);
            sasBuilder.SetPermissions(BlobSasPermissions.Read);

            // Add the SAS token to the container URI.
            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
            {
                // Specify the user delegation key.
                Sas = sasBuilder.ToSasQueryParameters(userDelegationKey,
                                                      blobClient.AccountName)
            };
            var sasToken = blobUriBuilder.Sas.ToString();
            return url + "?" + sasToken;
        }

任何人都可以帮助我解决这个问题。

编辑:

我们正在使用托管标识,当我们进行负载测试时,一些请求失败,但其中一些成功。

谢谢

4

1 回答 1

0

您能否尝试使用此代码生成 SAS 令牌

private static string GetSharedAccessSignature(
           string accountName,
           string accountkey,
           string blobContainer,
           string blobName,
           DateTimeOffset sharedAccessStartTime,
           DateTimeOffset sharedAccessExpiryTime)
    {
        var canonicalNameFormat = $"/blob/{accountName}/{blobContainer}/{blobName}";
        var st = sharedAccessStartTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
        var se = sharedAccessExpiryTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
        var sasVersion = "2016-05-31";
    
        string stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}", new object[]
        {
            "r",
            st,
            se,
            canonicalNameFormat,
            string.Empty,
            string.Empty,
            string.Empty,
            sasVersion,
            string.Empty,
            string.Empty,
            string.Empty,
            string.Empty,
            string.Empty
        });
    
        var sas = GetHash(stringToSign, accountkey);
    
        var credentials =
            $"?sv={sasVersion}&sr=b&sig={UrlEncoder.Default.Encode(sas)}&st={UrlEncoder.Default.Encode(st)}&se={UrlEncoder.Default.Encode(se)}&sp=r";
    
        string blobUri = $"https://{accountName}.blob.core.windows.net/{blobContainer}/{blobName}";
        return blobUri + credentials;
    }
    
    private static string GetHash(string stringToSign, string key)
    {
        byte[] keyValue = Convert.FromBase64String(key);
    
        using (HMACSHA256 hmac = new HMACSHA256(keyValue))
        {
            return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
        }
    }

有关更多详细信息,请参阅此SO 线程

于 2021-11-09T10:25:09.413 回答