You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure函数从Blob存储下载文件时遇认证错误求助

Azure Function中使用Azure.Storage.Blobs下载Blob时的认证错误问题

在Http触发的Azure Function中,使用Azure.Storage.Blobs库从Blob存储下载文件时,持续遇到认证错误,错误信息如下:

Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature

已验证连接字符串、账户密钥正确,且存储账户具备必要权限,但问题依旧。


相关代码

BlobStorage.cs

using Azure.Storage.Blobs;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Storage.Blob;
using System.IO.Compression;

public class BlobStorage : IBlobStorage
{
    
    private readonly ILogger<BlobStorage> _logger;
    private readonly BlobServiceClient _blobServiceClient;
    

    
    public BlobStorage(ILogger<BlobStorage> logger,
        BlobServiceClient blobServiceClient)
    {
        _logger = logger;
        _blobServiceClient = blobServiceClient;
    }
    
    
    public async Task<byte[]> GetBlobFilesAsZipAsync(string containerName, int days)
    {
        _logger.LogInformation("{class} -> {method} -> Start",
            nameof(BlobStorage), nameof(BlobStorage.GetBlobFilesAsZipAsync));

        await CreateContainerIfNotExistsAsync(containerName);

        var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
        var blobs = new List<CloudBlockBlob>();

        var resultSegment = containerClient.GetBlobsAsync().AsPages().GetAsyncEnumerator();

        while (await resultSegment.MoveNextAsync())
        {
            var blobPage = resultSegment.Current;

            foreach (var blobItem in blobPage.Values)
            {
                var blobClient = containerClient.GetBlobClient(blobItem.Name);
                var blobProperties = await blobClient.GetPropertiesAsync();
                var lastModified = blobProperties.Value.LastModified.UtcDateTime;

                //if ((DateTime.UtcNow - lastModified).TotalDays <= days)
                //{
                var cloudBlockBlob = new CloudBlockBlob(blobClient.Uri);
                blobs.Add(cloudBlockBlob);
                //}
            }
        }

        _logger.LogInformation("{class} -> {method} -> End",
            nameof(BlobStorage), nameof(BlobStorage.GetBlobFilesAsZipAsync));

        return await CreateZipFile(blobs); ;
    }

    
    

    private async Task CreateContainerIfNotExistsAsync(string containerName)
    {
        var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
        if (!await containerClient.ExistsAsync())
        {
            await containerClient.CreateAsync();
            _logger.LogInformation("Container {containerName} created if not exists.", containerName);
        }
    }

    /// <summary>
    /// CreateZipFile
    /// </summary>
    /// <param name="cloudBlockBlobs"></param>
    /// <returns></returns>
    private async Task<byte[]> CreateZipFile(IEnumerable<CloudBlockBlob> cloudBlockBlobs)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Update, true))
            {
                foreach (var file in cloudBlockBlobs)
                {
                    ZipArchiveEntry entry = archive.CreateEntry(file.Name);

                    using (Stream zipEntryStream = entry.Open())
                    using (MemoryStream blobStream = new MemoryStream())
                    {
                        await file.DownloadToStreamAsync(blobStream);
                        blobStream.Seek(0, SeekOrigin.Begin);
                        await blobStream.CopyToAsync(zipEntryStream);
                    }
                }
            }
            return ms.ToArray();
        }
    }
}

local.settings.json

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
  }
}

Startup.cs

builder.Services.AddSingleton(x =>
            new BlobServiceClient(connectionString: Environment.GetEnvironmentVariable("AzureWebJobsStorage")));

builder.Services.AddSingleton<IBlobStorage, BlobStorage>();

问题原因

代码中混合使用了新旧两个Azure Blob存储SDK:

  • 新SDK:Azure.Storage.Blobs(通过BlobServiceClient、BlobContainerClient、BlobClient操作)
  • 旧SDK:Microsoft.Azure.Storage.Blob(使用CloudBlockBlob)

创建CloudBlockBlob时仅传入了Blob的Uri,未携带任何认证凭据(如连接字符串、SAS令牌),导致调用DownloadToStreamAsync时无法生成有效的Authorization请求头,触发认证错误。


解决方案

1. 统一使用新SDK

移除对Microsoft.Azure.Storage.Blob NuGet包的引用,全程使用Azure.Storage.Blobs提供的API。

2. 修改代码逻辑

直接使用BlobClient处理Blob下载,它继承了BlobServiceClient的认证信息,无需额外配置凭据。修改后的关键代码如下:

// 修改GetBlobFilesAsZipAsync方法的集合类型
public async Task<byte[]> GetBlobFilesAsZipAsync(string containerName, int days)
{
    _logger.LogInformation("{class} -> {method} -> Start",
        nameof(BlobStorage), nameof(BlobStorage.GetBlobFilesAsZipAsync));

    await CreateContainerIfNotExistsAsync(containerName);

    var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
    var blobs = new List<BlobClient>(); // 改为BlobClient集合

    var resultSegment = containerClient.GetBlobsAsync().AsPages().GetAsyncEnumerator();

    while (await resultSegment.MoveNextAsync())
    {
        var blobPage = resultSegment.Current;

        foreach (var blobItem in blobPage.Values)
        {
            var blobClient = containerClient.GetBlobClient(blobItem.Name);
            var blobProperties = await blobClient.GetPropertiesAsync();
            var lastModified = blobProperties.Value.LastModified.UtcDateTime;

            //if ((DateTime.UtcNow - lastModified).TotalDays <= days)
            //{
            blobs.Add(blobClient); // 直接添加BlobClient
            //}
        }
    }

    _logger.LogInformation("{class} -> {method} -> End",
        nameof(BlobStorage), nameof(BlobStorage.GetBlobFilesAsZipAsync));

    return await CreateZipFile(blobs);
}

// 修改CreateZipFile方法的参数和实现
private async Task<byte[]> CreateZipFile(IEnumerable<BlobClient> blobClients)
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Update, true))
        {
            foreach (var blobClient in blobClients)
            {
                ZipArchiveEntry entry = archive.CreateEntry(blobClient.Name);

                using (Stream zipEntryStream = entry.Open())
                {
                    // 直接用BlobClient的DownloadToAsync方法写入压缩流
                    await blobClient.DownloadToAsync(zipEntryStream);
                }
            }
        }
        return ms.ToArray();
    }
}

3. 验证本地存储配置

如果使用本地模拟器,确保Azurite(或Azure Storage Emulator)已正常启动,local.settings.json中的AzureWebJobsStorage配置为UseDevelopmentStorage=true无误。


内容的提问来源于stack exchange,提问作者Rakesh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:10:00