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

Azure与ASP.NET Core 6 MVC:Blob存储图片高效获取方案咨询

无需SAS密钥,通过已认证用户直接用img标签访问Azure Blob存储图片

由于img标签无法自定义HTTP请求头,直接让前端携带Azure AD令牌访问Blob存储是不可行的。以下是两种符合你需求的解决方案,无需使用存储账户密钥生成的SAS:

方案1:使用用户委托SAS(User Delegation SAS)

这种SAS基于已认证用户的Azure AD身份生成,不依赖存储账户密钥,仅授权当前用户在有效期内访问指定Blob。

实现步骤:

  1. 配置Azure AD权限:

    • 在Azure门户中找到目标Blob容器,进入「访问控制(IAM)」页面。
    • 添加「存储Blob数据读取者」角色分配,选择已认证用户所属的AD组或单个用户,确保用户具备生成用户委托SAS的权限。
  2. 后端生成SAS URL接口:
    注入BlobServiceClient(建议通过配置文件读取连接字符串,而非硬编码),编写接口根据用户身份生成指定图片的SAS URL:

    private readonly BlobServiceClient _blobServiceClient;
    private readonly string _blobContainerName = "your-container-name";
    
    public ImageController(BlobServiceClient blobServiceClient)
    {
        _blobServiceClient = blobServiceClient;
    }
    
    [Authorize]
    [HttpPost("get-sas-urls")]
    public async Task<IActionResult> GetSasUrls([FromBody] List<string> imageNames)
    {
        // 获取当前用户的Azure AD访问令牌
        var accessToken = await HttpContext.GetTokenAsync("access_token");
        // 获取用户委托密钥,有效期1小时
        var userDelegationKey = await _blobServiceClient.GetUserDelegationKeyAsync(
            DateTimeOffset.UtcNow,
            DateTimeOffset.UtcNow.AddHours(1));
    
        var containerClient = _blobServiceClient.GetBlobContainerClient(_blobContainerName);
        var sasUrls = new List<string>();
    
        foreach (var imageName in imageNames)
        {
            var blobClient = containerClient.GetBlobClient(imageName);
            if (!await blobClient.ExistsAsync()) continue;
    
            var sasBuilder = new BlobSasBuilder
            {
                BlobContainerName = _blobContainerName,
                BlobName = imageName,
                Resource = "b", // 指定资源为Blob
                ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
            };
            sasBuilder.SetPermissions(BlobSasPermissions.Read);
            // 生成用户委托SAS令牌
            var sasToken = sasBuilder.ToSasQueryParameters(userDelegationKey, _blobServiceClient.AccountName).ToString();
            sasUrls.Add($"{blobClient.Uri}?{sasToken}");
        }
    
        return Json(sasUrls);
    }
    
  3. 前端调用渲染:
    通过Ajax调用上述接口拿到SAS URL列表,直接将img标签的src指向对应URL即可。

方案2:后端代理图片请求

通过后端接口代理图片访问,验证用户身份后直接流式返回Blob内容,完全无需SAS。

实现步骤:

  1. 配置应用服务托管标识权限:

    • 为你的Azure App Service启用系统托管标识。
    • 在Blob容器的「访问控制(IAM)」中,添加「存储Blob数据读取者」角色分配,选择该应用服务的托管标识。
  2. 后端代理接口:
    编写接口验证用户权限后,流式返回Blob内容:

    [Authorize]
    [HttpGet("images/{imageName}")]
    public async Task<IActionResult> GetImage(string imageName)
    {
        // 校验当前用户是否有权访问该图片所属的图库(根据你的业务逻辑实现)
        var hasAccess = await VerifyUserGalleryAccess(User, imageName);
        if (!hasAccess)
        {
            return Forbid();
        }
    
        var containerClient = _blobServiceClient.GetBlobContainerClient(_blobContainerName);
        var blobClient = containerClient.GetBlobClient(imageName);
        if (!await blobClient.ExistsAsync())
        {
            return NotFound();
        }
    
        // 流式返回Blob内容,避免加载到内存
        var stream = await blobClient.OpenReadAsync();
        // 根据图片实际类型调整MIME类型(如image/png、image/gif等)
        return File(stream, "image/jpeg");
    }
    
  3. 前端渲染:
    直接将img标签的src指向代理接口,例如:

    <img src="/api/images/your-image-name.jpg" alt="Gallery image">
    

现有代码优化建议

你当前的GetImagesFromBlob函数存在几个问题,建议调整:

  • 避免硬编码连接字符串,通过IConfiguration读取并注入BlobServiceClient。
  • 异步方法需用await调用,避免同步阻塞线程,将函数改为异步。
  • 无需遍历容器内所有Blob,直接根据数据库返回的图片名称定位对应Blob,提升效率。

内容的提问来源于stack exchange,提问作者Zdenek Barta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:37:15