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

基于用户委托密钥生成存储SAS密钥时遇访问拒绝问题排查

问题分析与解决方案

我根据官方文档构建了SAS密钥,步骤如下:

从Azure AD获取OAuth Token。使用OAuth生成用户委托密钥。使用用户委托密钥生成SAS Token

但访问Blob路径https://storage.blob.core.windows.net/container/dir/test.csv时遇到错误:

Access Denied. (message: 'Access to persistent storage path 'https://storage.blob.core.windows.net/container/dir/test.csv' was denied .

已拥有rwdl权限,以下是可能的操作错误点及修正方案:


核心错误点排查

1. SAS Token包含冗余参数

用户委托SAS不需要sv(API版本)参数,skv已指定用户委托密钥的版本,多余的sv会导致签名不匹配。需从SAS Token构建代码中移除s"sv=$apiVersion"项。

2. Canonical Resource格式验证

确保canonicalResource严格遵循/blob/<存储账户名>/<容器名>格式,例如存储账户名为mystorage、容器名为mycontainer时,应写为:

val canonicalResource = "/blob/mystorage/mycontainer"

无需添加Blob的具体路径(如dir/test.csv),因为是容器级SAS。

3. 签名字符串的换行符问题

构建stringToSign时,必须使用Unix换行符(\n),不能包含回车符(\r)。可打印生成的stringToSign确认格式是否正确。

4. 签名的URL编码方式

URLEncoder.encode可能存在编码偏差,建议直接替换Base64字符串中的特殊字符,确保符合Azure要求:

val signatureBase64 = Base64.getEncoder.encodeToString(signatureBytes)
val signatureEncoded = signatureBase64.replace("+", "%2B").replace("/", "%2F").replace("=", "%3D")

5. 用户委托密钥的服务类型验证

确认从XML获取的signedService值为b(Blob服务),若服务类型不匹配会直接导致权限被拒。


修正后的关键代码片段

移除冗余参数的SAS Token构建

val sasToken = Seq(
  s"sp=$permissions",
  s"st=$sasStart",
  s"se=$sasExpiry",
  s"skoid=$signedOid",
  s"sktid=$signedTid",
  s"skt=$signedKeyStart",
  s"ske=$signedKeyExpiry",
  s"sks=$signedService",
  s"skv=$signedVersion",
  s"spr=$protocol",
  s"sr=$resource",
  s"sig=$signatureEncoded"
).mkString("&")

正确的签名编码方式

val keyBytes = Base64.getDecoder.decode(keyValue)
val mac = Mac.getInstance("HmacSHA256")
mac.init(new SecretKeySpec(keyBytes, "HmacSHA256"))
val signatureBytes = mac.doFinal(stringToSign.getBytes("UTF-8"))
val signatureBase64 = Base64.getEncoder.encodeToString(signatureBytes)
val signatureEncoded = signatureBase64.replace("+", "%2B").replace("/", "%2F").replace("=", "%3D")

额外检查项

  • 确认生成用户委托密钥的OAuth Token对应的主体(用户/服务主体)拥有Storage Blob Data Contributor或更高数据权限(仅订阅/资源组权限无效)。
  • 检查SAS生效时间:sasStart为当前时间减5分钟,sasExpiry为加1小时,确保当前时间在有效期内。
  • 验证Blob访问路径的存储账户名、容器名是否与代码中的配置完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 10:44:55