'Server failed to authenticate the request' 尝试为 (Azurite) Azure BLOB 存储生成 SAS URI

'Server failed to authenticate the request' when attempting to generate SAS URI for (Azurite) Azure BLOB storage

我梳理了这个问题的至少十几个不同版本,但到目前为止,其中 none 已经为我所遇到的问题提供了答案。我正在尝试开发一个概念验证,用于使用 Azurite 和具有相应存储帐户密钥的服务 SAS 从 Azure BLOB 存储检索图像。我使用众所周知的 Azurite 存储帐户凭据,如 here. There appear to be innumerable ways to do this kind of thing in C# but I opted to loosely follow this example 所示,结果如下:

public Uri GetSharedKeySasUrl()
{
    BlobServiceClient serviceClient = new BlobServiceClient(
        new Uri("http://127.0.0.1:10000/devstoreaccount1/"),
        new Azure.Storage.StorageSharedKeyCredential(
            "devstoreaccount1",
            "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
        )
    );

    var blobContainer = serviceClient.GetBlobContainerClient("images");

    var blobClient = blobContainer.GetBlobClient("00000-pano.jpg");

    BlobSasBuilder sasBuilder = new BlobSasBuilder()
    {
        BlobContainerName = "images",
        BlobName = "00000-pano.jpg",
        Resource = "b",
        StartsOn = DateTimeOffset.UtcNow,
        ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
    };

    sasBuilder.SetPermissions(BlobSasPermissions.Read);

    Uri sasUri = blobClient.GenerateSasUri(sasBuilder);
    Debug.WriteLine("SAS URI for blob is: {0}", sasUri);

    return sasUri;
}

这会产生一个 URL, 看起来 好像它应该可以正常工作,但是每当我将它粘贴到浏览器并尝试访问它时,我总是得到以下:

<Error>
    <Code>AuthorizationFailure</Code>
    <Message>Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature. RequestId:551902dd-ecb8-4736-9cf1-32406d98c02f Time:2022-04-11T20:18:06.368Z</Message>
</Error>

相反,如果我通过 Microsoft Azure 存储资源管理器生成 SAS 签名,那么 URL 可以完美运行。如果我将此 URL 与此方法生成的 URL 进行比较,两者的格式似乎都非常正确 - 我看不到任何表明我的格式错误的信息。

Generated by the method:
http://127.0.0.1:10000/devstoreaccount1/images/00000-pano.jpg?sv=2021-04-10&st=2022-04-11T20%3A17%3A59Z&se=2022-04-11T21%3A17%3A59Z&sr=b&sp=r&sig=bUHI2562NmvvtflOqT5kr0E%2BnZv7Q12PlR%2FGNPmEhL8%3D

Generated in Storage Explorer:
http://127.0.0.1:10000/devstoreaccount1/images/00000-pano.jpg?sv=2018-03-28&st=2022-04-11T20%3A06%3A47Z&se=2022-04-12T20%3A06%3A47Z&sr=b&sp=r&sig=V6N7uWDGgoVx8wirM%2FP1ou2kbg05PB4D%2BG8YQdvS5RU%3D

唯一显着的区别似乎是每个人使用的服务版本 - 资源管理器使用 2018-03-28 而方法使用 2021-04-10。我试过在 BlobSasBuilder 中分配版本,但它只是被忽略了,这与微软自己关于 属性 被弃用和 class 始终使用最新支持的服务版本的评论一致,无论您在此处指定的内容。不过,我仍然认为这不能解释问题。

有什么想法吗?在此先感谢您的帮助。

编辑

我仍然绝望地坚持这一点。我已经多次尝试重新制定我用来构建 SAS URI 的代码,希望能有所作为。到目前为止,没有一个有效。我试过的方法:

我还使用不同的启动选项对 运行 Azurite 进行了试验,包括 azurite --looseazurite --skipApiVersionCheck。两者都没有任何区别。

我尝试过的其他事情:

我简直无法理解为什么这是一个如此难以逾越的难题。请帮忙。

请检查以下几点:

请确保您已分配 Storage Blob Data Contributor 角色或 storage blob data reader 角色。导航至 存储帐户 -> 访问控制 (IAM) -> 添加角色分配 或要求管理员分配该角色。

还要检查容器的访问级别并将访问级别更改为读取 blob(如果它是私有的)。 就我而言,我也是我的存储帐户的管理员,并且已启用读取、写入和创建 sas 权限。

-请检查本地计算机是否有任何时区差异(时间戳不同步)。

另请检查您的存储帐户是否启用了防火墙

  • Azure 门户 -> 存储帐户 -> 网络 -> 检查允许访问 来自(所有网络/选定网络)
  • 如果是“Selected Networks” - 表示存储帐户是 防火墙已启用。
  • 如果存储帐户启用了防火墙,这可能是 错误,因此请检查您的存储是否已列入白名单以供访问,因为默认情况下其 IP 为 127.0.0.1:10000.
  • 另外检查 SAS 是否已过期

请检查 https 端点: SO reference :add a file to Azurite

最简单的方法是在应用配置文件中使用连接字符串

<appSettings>
  <add key="StorageConnectionString" value="UseDevelopmentStorage=true" />
</appSettings>

注意:在 github.

中保持与 Azurite/issues 类似的曲目

带连接字符串:

    var connectionString = "DefaultEndpointsProtocol=https;AccountName=.........";
    BlobServiceClient _blobServiceClient = new BlobServiceClient(connectionString);
   // var blobUri = _blobServiceClient.GenerateAccountSasUri(
   AccountSasPermissions.Read, DateTimeOffset.UtcNow.AddDays(10),
   AccountSasResourceTypes.Object);

   // var sasCredential = new AzureSasCredential(blobUri.Query);
    
    var blobContainerClient = _blobServiceClient.GetBlobContainerClient("imagecont");  //container name
    var blobClient = blobContainerClient.GetBlobClient("computeimage.jpg"); // my image blob name
                                                                     
    var sasBuilder = new BlobSasBuilder()
    {
        BlobContainerName = blobClient.BlobContainerName,
        BlobName = blobClient.Name,
        Resource = "b", // b for blob, c for container
        StartsOn = DateTimeOffset.UtcNow,
        ExpiresOn = DateTimeOffset.UtcNow.AddHours(2),
    };
  
     
    sasBuilder.SetPermissions(BlobSasPermissions.Read); // read permissions
                                                       
    Uri sasUri = blobClient.GenerateSasUri(sasBuilder);
  
    Console.WriteLine("SAS URI for blob is: {0}", sasUri);

使用连接字符串和(SAS 密钥)帐户密钥获取 blob 的 SAS 令牌:

var connectionString = "DefaultEndpointsProtocol=h.......";
             BlobServiceClient _blobServiceClient = new BlobServiceClient(connectionString);
              var storageAccountName = " ";

var blobContainerClient = _blobServiceClient.GetBlobContainerClient("imagecont");
            var blobClient = blobContainerClient.GetBlobClient("computeimage.jpg"); // blob name


//Here we have used SAS  Key StorageSharedKeyCredential(storageAccountName,Account key);

            StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, "hmjkxxxxxxX3A==");
            var sasBuilder = new BlobSasBuilder()
            {
                BlobContainerName = blobClient.BlobContainerName,
                BlobName = blobClient.Name,
                Resource = "b", // b for blob
                StartsOn = DateTimeOffset.UtcNow,
                ExpiresOn = DateTimeOffset.UtcNow.AddHours(2),
            };
            sasBuilder.SetPermissions(BlobSasPermissions.Read); // read permissions
            string sasToken = sasBuilder.ToSasQueryParameters(sharedKeyCredential).ToString();
Console.WriteLine("SAS token for blob is: {0}", sasToken);

输出 SAS 令牌:

表格urlhttps://<storage account name>.blob.core.windows.net/<container>/<blob name ex: computeimage.jpg >?<give sas token here> 并使用端点获取/检索图像


输出检索图像两种方式(从URL和从SAS令牌形成URL)

参考文献:

  1. azure-storage-net/issues(GITHUB)

更新的解决方案:

我已经测试了 Azure.Storage.Blobs 软件包版本 12.11.0,它给出了问题中描述的确切问题 OP。

将其更改为版本 12.10.0 解决了问题。

由此得出结论,版本 12.11.0 必须是重大更改或错误的副作用。

因此,在 Microsoft 提供解决方案或答案之前,解决方案是使用版本 12.10.0。


原回答:

我已经测试了你的代码并且它有效,我没有得到你的错误。我想您要么需要重新安装最新版本的 Azurite,要么按照我的方式安装,它对我有用。

为了保证工作的一致性,我使用了docker来安装蓝晶

我使用 Windows 11 和 Docker 桌面,有关安装的更多信息请查看 Microsoft doc

docker pull mcr.microsoft.com/azure-storage/azurite

然后

docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -v c:/azurite:/data mcr.microsoft.com/azure-storage/azurite

现在我们有 docker up 和 运行ning,我使用 Microsoft Azure Storage Explorer 创建一个 blob 容器并上传图像 00000-pano.jpg(这是一个花卉图像).

现在我在不更改任何内容的情况下获取您的代码,然后 运行 在我的控制台应用程序中使用包引用

<PackageReference Include="Azure.Storage.Blobs" Version="12.10.0" />

和运行宁代码,我得到以下URL:

http://127.0.0.1:10000/devstoreaccount1/images/00000-pano.jpg?sv=2020-08-04&st=2022-04-20T10%3A47%3A00Z&se=2022-04-20T11%3A47%3A00Z&sr=b&sp=r&sig=RHHe5NJRjhbOjoTeCONqhrRHjjJCygOa8urcwzOWpeE%3D

我将 URL 复制并粘贴到我的浏览器中,我得到了花,没有身份验证问题:

以下是我的 docker 控制台和我对图像所做的操作的日志:

Disclaimer: I have some articles about Azurite and docker, testing Azure code with Azurite, and mocking Azure storage this might add value for your further work. (https://itbackyard.com/tag/azurite/)

更新

我在 submitting a bug to the Azure SDK team that the fix for this is actually being handled on the Azurite side, per these previously identified issues. It appears Azurite simply doesn't support SAS versions 2020-10-02 and newer at this time. Worth keeping an eye on this one 之后发现那些希望使用最新 SAS 版本进行本地开发的人。

原答案

这是一个版本控制问题。无论出于何种原因,最新版本的 Azure.Storage.Blobs(12.11.0,在撰写本文时)绝对拒绝与 Azurite 一起使用,但版本 12.10.0 工作正常。

新版本似乎发生了某种重大变化。我已经向 SDK 团队提交了一个错误,只是为了增加一些可见性。与此同时,我想我会坚持使用 12.10.0 版。

我遇到了与 OP 完全相同的问题,但技术略有不同:

  • Azurite 3.16.0(Docker 图片)
  • Azure 存储 Blob Java SDK 12.15.0
  • @azure/storage-blob Java脚本 SDK 12.9.0

在我的应用程序中,我使用 Java SDK 生成 SAS,然后将其传递给浏览器中的 JavaScript 应用程序 运行,然后将文件上传到 Azure存储 blob 容器。
我的 SAS 生成器代码明确使用 BlobServiceVersion.V2021_04_10

我的 SAS 生成器代码:

BlobContainerClient container = new BlobContainerClientBuilder()
  .credential(azuriteStorageCredential())
  .endpoint(endpoint)
  .containerName(containerName)
  .serviceVersion(BlobServiceVersion.V2021_04_10)
  .buildClient();
BlobClient blob = container.getBlobClient(blobName);
OffsetDateTime expiration = OffsetDateTime
  .now()
  .plusMinutes(30);
BlobSasPermission permissions = new BlobSasPermission()
  .setCreatePermission(true);
BlobServiceSasSignatureValues values = new BlobServiceSasSignatureValues(expiration, permissions)
  .setContentType("video/mp4")
  .setProtocol(SasProtocol.HTTPS_HTTP);
String sas = blob.generateSas(values);
String url = blob.getBlobUrl() + "?" + sas; // the final blob url passed to my javascript app

Java脚本代码

const options = {
  blobHTTPHeaders: {
    blobContentType: 'video/mp4'
  }
};
const client = new BlockBlobClient(url);
client.uploadData(file, options);

我也使用了 Azurite 的 well-known 存储帐户凭据并不断获得 Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature 但我终究无法弄清楚为什么 Azurite 拒绝 SAS。

我在 Azurite 中打开详细日志记录并注意到签名不匹配但无法确定原因。

我也尝试了很多不同的方法来做同样的事情,然后最终偶然发现了这个 Whosebug post 并决定尝试升级库。

我升级到:

  • 蓝铜矿 3.17.1
  • Azure 存储 Blob Java SDK 12.16.0

令人惊讶的是...它终于奏效了!
所以问题出在 Azurite 或 Java SDK 中...

我没有费心去单独降级它们来试图找出问题所在,但我想我会 post 在这里为使用这些相同的 SDK + Azurite 遇到类似问题的任何人提供这个。

更新:基于this comment,该错误似乎在 Azurite 中,并已在 3.17.0

中修复