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

通过PowerShell REST API生成Azure Blob SAS令牌及认证报错解决

Azure存储PowerShell REST API生成SAS/认证报错解决方案

核心错误点

  • 你混淆了Shared Key认证和SAS令牌认证两种认证逻辑:代码里构造的是SAS的签名字段,最终请求头却用了SharedKey的授权格式,两种认证的StringToSign规则完全不同
  • 换行符使用错误:PowerShell里的换行符要用`n而不是\n,\n在PowerShell字符串里会被当成普通字符处理,不会解析为换行
  • StringToSign不符合规范:从服务端返回的待签名字符串可以看到,2012-02-12版本的Blob服务Get操作的Shared Key待签名字符串需要包含HTTP动词、内容长度、请求头、资源路径等多个字段,空字段也要留空占位,你自行构造的StringToSign缺失了大量必填字段
  • 变量大小写不一致:代码里signedpermissions和signedPermissions、signedstart和signedStart大小写不统一,拼接时可能取到空值
  • 你最终需求是生成SAS令牌,不需要用Shared Key请求头,直接把签名后的参数拼接成查询字符串附加到资源URL即可

修复后的可运行代码(纯原生PowerShell,无需Az模块)

Function Get-MyBlob {
    param(
        [string]$StorageAccountName,
        [string]$StorageContainerName,
        [string]$BlobName,
        [string]$StorageAccountKey,
        [string]$Permissions = "r",
        [int]$ValidityHours = 24
    )

    # 时间必须转换为UTC时间,格式符合ISO 8601标准
    $startTime = (Get-Date).ToUniversalTime()
    $expiryTime = $startTime.AddHours($ValidityHours)
    $signedStart = $startTime.ToString("yyyy-MM-ddTHH:mm:ssZ")
    $signedExpiry = $expiryTime.ToString("yyyy-MM-ddTHH:mm:ssZ")
    $signedVersion = "2021-06-08" # 可替换为你需要的API版本
    $signedResource = "b" # b代表Blob级别,c代表容器级别
    $canonicalizedResource = "/blob/$StorageAccountName/$StorageContainerName/$BlobName"

    # 严格按SAS规范构造待签名字符串,空字段必须留空占位,顺序不能调换
    $StringToSign = @(
        $Permissions,
        $signedStart,
        $signedExpiry,
        $canonicalizedResource,
        "", 
        "", 
        "https",
        $signedVersion,
        $signedResource,
        "", 
        "", 
        "", 
        "", 
        "", 
        ""  
    ) -join "`n"

    # 计算HMACSHA256签名
    $sharedKey = [System.Convert]::FromBase64String($StorageAccountKey)
    $hasher = [System.Security.Cryptography.HMACSHA256]::new($sharedKey)
    $signature = [System.Convert]::ToBase64String($hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($StringToSign)))

    # 拼接SAS查询参数,特殊字符需要URL编码
    $sasParams = [ordered]@{
        sv = $signedVersion
        st = [System.Web.HttpUtility]::UrlEncode($signedStart)
        se = [System.Web.HttpUtility]::UrlEncode($signedExpiry)
        sr = $signedResource
        sp = $Permissions
        spr = "https"
        sig = [System.Web.HttpUtility]::UrlEncode($signature)
    }

    $sasToken = ($sasParams.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" }) -join "&"
    $blobUrl = "https://$StorageAccountName.blob.core.windows.net/$StorageContainerName/$BlobName?$sasToken"

    # 直接用带SAS的URL请求,不需要额外添加授权头
    return Invoke-RestMethod -Uri $blobUrl -Method Get
}

# 调用示例
Get-MyBlob -StorageAccountName "MYSTORAGEACCOUNT" -StorageContainerName "MYCONTAINER" -BlobName "coloured-paper.jpg" -StorageAccountKey "MYSTORAGEACCOUNTACCESSKEY"

额外说明

  • 如果需要生成容器级别的SAS,只需把signedResource改为c,canonicalizedResource改为/blob/$StorageAccountName/$StorageContainerName即可
  • 签名参数的顺序不能随意调换,必须严格按规范顺序拼接,否则会出现签名不匹配的错误
  • 所有时间必须使用UTC时间,否则会出现时间不在有效期内的报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 17:48:04