使用Azurite执行PUT操作时共享密钥生成失败,返回403错误
问题描述
尝试使用Azurite发起PUT Blob请求,参数如下:
account = "devstoreaccount1" key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" api_version = "2021-06-08" block_type = "BlockBlob"
构造的签名字符串:
string_to_sign = (f"PUT\n" # HTTP method f"\n" # Content-Encoding f"\n" # Content-Language f"0\n" # Content-Length f"\n" # Content-MD5 f"\n" # Content-Type f"\n" # Date f"\n" # If-Modified-Since f"\n" # If-Match f"\n" # If-None-Match f"\n" # If-Unmodified-Since f"\n" # Range f"x-ms-date:{date_str}\n" f"x-ms-version:{api_version}\n" f"x-ms-blob-type:{block_type}\n" f"/{account}/{container}/{blob}")
每次请求均返回403认证失败,错误信息:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Error> <Code>AuthorizationFailure</Code> <Message>Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature. RequestId:35ee2117-c03a-417d-84dd-be4a0b4d1163 Time:2024-10-29T16:04:11.193Z</Message> </Error>
使用的Python代码:
import hmac import hashlib import base64 from datetime import datetime def main(): authorization, date, api_version = blobs() print(f"Authorization: {authorization}") print(f"Date: {date}") print(f"API Version: {api_version}") input("Press any key to exit...") def blobs(): account = "devstoreaccount1" key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" # Replace with your access key container = "container" blob = "file.txt" api_version = "2021-06-08" block_type = "BlockBlob" dt = datetime.utcnow() date_str = dt.strftime('%a, %d %b %Y %H:%M:%S GMT') string_to_sign = (f"PUT\n" # HTTP method f"\n" # Content-Encoding f"\n" # Content-Language f"0\n" # Content-Length f"\n" # Content-MD5 f"\n" # Content-Type f"\n" # Date f"\n" # If-Modified-Since f"\n" # If-Match f"\n" # If-None-Match f"\n" # If-Unmodified-Since f"\n" # Range f"x-ms-date:{date_str}\n" f"x-ms-version:{api_version}\n" f"x-ms-blob-type:{block_type}\n" f"/{account}/{account}/{container}/{blob}") signature = sign_this(string_to_sign, key) # Updated Authorization format authorization = f"SharedKey {account}:{signature}" return authorization, date_str, api_version def sign_this(string_to_sign, key): decoded_key = base64.b64decode(key) string_to_sign = string_to_sign.encode('utf-8') hmac_sha256 = hmac.new(decoded_key, string_to_sign, hashlib.sha256) signature = base64.b64encode(hmac_sha256.digest()).decode('utf-8') return signature if __name__ == "__main__": main()
将代码生成的Authorization值替换到Postman的请求头中,问题依旧,请问哪里出错了?
问题排查与修复
你的代码和签名字符串构造存在两个关键错误:
1. 资源路径重复账户名
代码中构造的路径为/{account}/{account}/{container}/{blob},多写了一个{account},导致路径变成/devstoreaccount1/devstoreaccount1/container/file.txt,与实际请求的资源路径不匹配,直接导致签名验证失败。正确的路径格式应为/{account}/{container}/{blob}。
2. x-ms头部排序错误
Azure Storage的SharedKey认证要求所有x-ms开头的请求头必须按字典序排序后加入签名字符串。你当前的顺序是x-ms-date、x-ms-version、x-ms-blob-type,正确的字典序应为x-ms-blob-type、x-ms-date、x-ms-version,顺序错误会导致签名不匹配。
修复后的签名字符串
修改上述两个问题后的代码片段:
string_to_sign = (f"PUT\n" f"\n" # Content-Encoding f"\n" # Content-Language f"0\n" # Content-Length f"\n" # Content-MD5 f"\n" # Content-Type f"\n" # Date f"\n" # If-Modified-Since f"\n" # If-Match f"\n" # If-None-Match f"\n" # If-Unmodified-Since f"\n" # Range f"x-ms-blob-type:{block_type}\n" f"x-ms-date:{date_str}\n" f"x-ms-version:{api_version}\n" f"/{account}/{container}/{blob}")
额外验证点
- 确保请求时的
x-ms-date与签名时使用的date_str完全一致,时间差不能超过15分钟(Azure的时间窗口限制); - 确认请求头包含所有签名字符串中的x-ms头部,不能多也不能少;
- 检查Azurite服务是否正常运行,端点和端口配置是否正确。
内容的提问来源于stack exchange,提问作者entropy283
相关产品推荐
相关产品推荐

