纯JavaScript查询Azure Table Storage 按分区键行键筛选报签名认证错误
错误原因
签名校验失败的核心原因是签名字符串中包含的资源路径,与实际发起请求的资源路径不匹配:
- 全表查询时,请求路径为
/<存储账户名>/sales,和你构造签名时写入的路径完全一致,因此认证可以正常通过。 - 按分区键、行键查询单个实体时,实际请求的资源路径为
/<存储账户名>/sales(PartitionKey='CAR1748',RowKey='1'),但你构造签名时仍然使用了截断的/<存储账户名>/sales作为签名输入,Azure服务端会用实际请求路径重新计算签名,和你传入的签名值无法匹配,直接返回授权错误。 - 额外问题:你错误使用
encodeURIComponent编码了整个请求路径,会把括号、单引号等合法路径字符转义,进一步导致路径和签名输入不一致。
修正方法
构造签名时,必须保证签名字符串里的资源路径和实际请求的路径(域名后、查询参数前的部分)完全一致,不要随意截断或全局编码路径。
修正后的核心代码如下:
var storageAccount = 'xxxxxxxxx'; var accountKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; var date = new Date(); var UTCString = date.toUTCString(); var tableName = 'sales'; var pk = "CAR1748"; var rk = "1"; // 提前定义和实际请求完全一致的资源路径,不做全局编码 var resourcePath = "/" + storageAccount + "/" + tableName + "(PartitionKey='" + pk + "',RowKey='" + rk + "')"; // 签名时直接使用完整资源路径 var dataToEncode = UTCString + "\n" + resourcePath; var hash = CryptoJS.HmacSHA256(dataToEncode, CryptoJS.enc.Base64.parse(accountKey)); var strSignature = CryptoJS.enc.Base64.stringify(hash); var auth = "SharedKeyLite " + storageAccount + ":" + strSignature; // 拼接请求地址,不要对路径整体做encodeURIComponent var path = "https://" + storageAccount + ".table.core.windows.net/" + tableName + "(PartitionKey='" + pk + "',RowKey='" + rk + "')"; var header = { "Accept" : "application/json;odata=nometadata", "x-ms-date" : UTCString , "Authorization" : auth , "x-ms-version": "2021-06-08", "DataServiceVersion": "3.0;NetFx", "MaxDataServiceVersion": "3.0;NetFx" }; try { var response = https.get({ url: path, headers: header }); context.response.write(response.code); } catch (e) { context.response.write(response.body); return true; }
额外注意事项
- 如果后续使用
$filter等查询参数做筛选,Table服务的SharedKeyLite签名不需要把查询参数加入签名字符串,只需要保证路径部分和签名输入完全一致即可。 - 路径中如果包含中文等特殊字符,只需要对特殊字符部分做编码,且编码后的值要同时同步到签名的资源路径中,保证两边完全一致。
内容的提问来源于stack exchange,提问作者user3665103
相关产品推荐
相关产品推荐

