使用Account SAS获取Azure Blob容器属性时认证失败
问题描述
我能成功生成Service SAS来列出容器内的Blob,但使用Account SAS获取容器属性时,返回认证失败错误:
<?xml version="1.0" encoding="utf-8"?> <Error> <Code>AuthenticationFailed</Code> <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:63a5ec3b-601e-0016-4e07-4a125b000000 Time:2024-01-18T12:08:26.1877828Z</Message> <AuthenticationErrorDetail>Signature did not match. String to sign used was devreferenceapidatasa rwl b sc 2024-01-18T12:07:27Z 2024-01-18T12:17:27Z https 2023-11-03 </AuthenticationErrorDetail> </Error>
我参考相关文档后写出如下JS代码:
var accountName = "reference-data"; var signedPermissions = "rwl"; var signedService = "b"; var signedStart = start; var signedExpiry = end; var signedResourceType = "sc"; var signedProtocol = "https"; var signedVersion = "2023-11-03"; function generateSas(storageAccountKey, input) { input = decodeURI(input) const keyBytes = CryptoJS.enc.Base64.parse(storageAccountKey) const hash = CryptoJS.HmacSHA256(input, keyBytes) const hashB64 = CryptoJS.enc.Base64.stringify(hash) const hashB64UriEncoded = encodeURIComponent(hashB64) return hashB64UriEncoded } var stringToSign = accountName + "\n" + signedPermissions + "\n" + signedService + "\n" + signedResourceType + "\n" + signedStart + "\n" + signedExpiry + "\n" + signedProtocol + "\n" + signedVersion + "\n" var key = MY_KEY; const sig = generateSas(key, stringToSign) var sasToken = `sv=${signedVersion}&ss=${signedService}&srt=${signedResourceType}&sp=${signedPermissions}&st=${signedStart}&se=${signedExpiry}&spr=${signedProtocol}&sig=${sig}`; var url = `https://devreferenceapidatasa.blob.core.windows.net/reference-data?restype=container&${sasToken}`
问题分析与修复
从错误返回的String to sign可以定位到三个核心问题:
账户名称不匹配
错误签名串开头是devreferenceapidatasa,但代码里的accountName写的是reference-data,必须改为存储账户的实际名称(即URL中的devreferenceapidatasa)。签名串格式缺失必填占位行
Azure存储账户SAS签名串(2020-02-10及以上版本)要求严格的字段顺序,即使不需要限制IP,也要保留signed-IP的空行占位。你的签名串跳过了这个字段,导致格式错位。多余的decodeURI操作
签名串不需要解码,直接传入原始字符串即可,去掉input = decodeURI(input)会避免破坏签名串的原始格式。
修正后的完整代码:
var accountName = "devreferenceapidatasa"; // 改为实际存储账户名称 var signedPermissions = "rwl"; var signedService = "b"; var signedStart = start; var signedExpiry = end; var signedResourceType = "sc"; var signedProtocol = "https"; var signedVersion = "2023-11-03"; function generateSas(storageAccountKey, input) { const keyBytes = CryptoJS.enc.Base64.parse(storageAccountKey) const hash = CryptoJS.HmacSHA256(input, keyBytes) const hashB64 = CryptoJS.enc.Base64.stringify(hash) const hashB64UriEncoded = encodeURIComponent(hashB64) return hashB64UriEncoded } var stringToSign = accountName + "\n" + signedPermissions + "\n" + signedService + "\n" + signedResourceType + "\n" + signedStart + "\n" + signedExpiry + "\n" + "" + "\n" + // 保留signed-IP的空行占位 signedProtocol + "\n" + signedVersion + "\n" var key = MY_KEY; const sig = generateSas(key, stringToSign) var sasToken = `sv=${signedVersion}&ss=${signedService}&srt=${signedResourceType}&sp=${signedPermissions}&st=${signedStart}&se=${signedExpiry}&spr=${signedProtocol}&sig=${sig}`; var url = `https://devreferenceapidatasa.blob.core.windows.net/reference-data?restype=container&${sasToken}`
内容的提问来源于stack exchange,提问作者dq101
相关产品推荐
相关产品推荐

