Azure SAS Token未授权问题:如何实现无IP白名单的限时公网访问
场景
前端(React单页应用)调用部署在AKS中的后端API传入Blob文件名,后端生成有效期15分钟的Blob文件SAS Token。但前端使用该Token时提示未授权错误,仅将浏览器IP加入白名单后才可访问Blob文件。
错误信息
This XML file does not appear to have any style information associated with it. The document tree is shown below.
return (<Code>AuthorizationFailure</Code> )This request is not authorized to perform this operation. RequestId:b9efa22e-001e-004c-23f9-274133000000 Time:2023-12-06T04:07:47.4688222Z
后端代码实现
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Azure.Storage.Blobs; using Azure.Storage.Sas; using System; using Azure.Storage; namespace SAS.Container.Controllers { [ApiController] [Route("api/get-sas")] public class GetSasAzureStorageController : ControllerBase { private readonly IConfiguration _configuration; public GetSasAzureStorageController(IConfiguration configuration) { _configuration = configuration; } [HttpGet("")] public IActionResult GetSasToken() { try { string connectionString = _configuration.GetConnectionString("AzureStorageConnection"); if (string.IsNullOrEmpty(connectionString)) { return BadRequest("AzureStorageConnection is not configured in appsettings.json"); } BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString); string containerName = "assets"; string blobName = "myblob.png"; var accountKey="myaccountKey"; BlobClient blobClient = blobServiceClient.GetBlobContainerClient(containerName).GetBlobClient(blobName); // Set permissions for SAS token BlobSasBuilder sasBuilder = new BlobSasBuilder() { BlobContainerName = containerName, BlobName = blobName, Resource = "b", // 'b' for blob StartsOn = DateTimeOffset.UtcNow, ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(15) }; // set permission read for SAS token sasBuilder.SetPermissions(BlobSasPermissions.Read); // Generate SAS token BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri) { Sas = sasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(blobServiceClient.AccountName,accountKey )) }; var sastoken = blobUriBuilder.ToUri().ToString(); return Ok(new { sastoken }); } catch (Exception ex) { return StatusCode(500, $"An error occurred: {ex.Message}"); } } } }
疑问
- 该问题原因是什么?
- 如何让SAS Token无需客户端IP白名单即可提供限时公网访问权限?
问题原因
你的Azure存储账户或目标Blob容器配置了IP防火墙规则,该规则会优先于SAS令牌权限生效:只有在白名单内的IP才能访问存储资源,不在白名单的客户端请求即使携带有效SAS令牌,也会被防火墙直接拦截,返回AuthorizationFailure错误。
解决方案
方案1:配置存储账户允许SAS令牌绕过IP防火墙
这是最直接的解决方案,步骤如下:
- 登录Azure门户,进入目标存储账户
- 切换到网络选项卡,选择防火墙和虚拟网络设置
- 在页面下方找到允许受信任的Microsoft服务访问此存储账户区域,勾选允许使用SAS令牌的请求绕过防火墙
- 保存修改
完成后,携带有效SAS令牌的请求将不受IP防火墙限制,无需添加客户端IP白名单即可访问Blob。
方案2:生成SAS时动态指定允许的IP范围(可选)
如果不想完全放开防火墙,可在生成SAS令牌时指定允许的客户端IP,修改代码中BlobSasBuilder的配置:
// 替换为前端请求的真实IP,注意AKS环境需配置反向代理传递真实客户端IP var clientIp = Request.HttpContext.Connection.RemoteIpAddress; BlobSasBuilder sasBuilder = new BlobSasBuilder() { BlobContainerName = containerName, BlobName = blobName, Resource = "b", // 'b' for blob StartsOn = DateTimeOffset.UtcNow, ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(15), IPRange = new SasIPRange(clientIp) };
此方案适合需要精细控制SAS使用IP范围的场景,但需要确保后端能正确获取前端真实IP。
额外检查项
- 确认存储账户密钥有效且具备生成SAS令牌的权限
- 验证生成的SAS令牌包含正确的
Read权限、有效期参数 - 检查Blob容器访问级别为私有(这是正常的,私有容器必须通过SAS或Azure AD授权访问)
内容的提问来源于stack exchange,提问作者agungardiyanta

