[英]Azure BLOB PUT Rest api - Not able to authenticate with Python
I'm trying to create a Blob in an Azure Container by using Python and the Azure Blob Rest API. I'm trying to create a Blob in an Azure Container by using Python and the Azure Blob Rest API. it has been an interesting exercise as it's my first time interacting with Azure Rest APIs.
这是一个有趣的练习,因为这是我第一次与 Azure Rest API 交互。 I've read the MS documentation about it and also read many questions in this site and according to them my code seems correct however I am not able to make a successful PUT yet.
我已经阅读了有关它的 MS 文档,还阅读了该站点中的许多问题,根据它们,我的代码似乎是正确的,但是我还不能成功 PUT。 I'm able to execute GET requests (list containers/blobs).
我能够执行 GET 请求(列出容器/blob)。
Following the code:按照代码:
import requests
import datetime
import hmac
import hashlib
import base64
storage_account_name = '<mystorageaccount>'
storage_account_key = '<mystoragekey>'
container_name='test'
api_version = '2015-02-21'
request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
string_params = {
'verb': 'PUT',
'Content-Encoding': '',
'Content-Language': '',
'Content-Length': '11',
'Content-MD5': '',
'Content-Type': 'text/plain; charset=UTF-8',
'Date': '',
'If-Modified-Since': '',
'If-Match': '',
'If-None-Match': '',
'If-Unmodified-Since': '',
'Range': '',
'CanonicalizedHeaders': 'x-ms-blob-type:BlockBlob' + '\nx-ms-date:' + request_time + '\nx-ms-version:' + api_version,
'CanonicalizedResource': '/' + storage_account_name +'/'+container_name+ '/' +'fname'
}
string_to_sign = (string_params['verb'] + '\n'
+ string_params['Content-Encoding'] + '\n'
+ string_params['Content-Language'] + '\n'
+ string_params['Content-Length'] + '\n'
+ string_params['Content-MD5'] + '\n'
+ string_params['Content-Type'] + '\n'
+ string_params['Date'] + '\n'
+ string_params['If-Modified-Since'] + '\n'
+ string_params['If-Match'] + '\n'
+ string_params['If-None-Match'] + '\n'
+ string_params['If-Unmodified-Since'] + '\n'
+ string_params['Range'] + '\n'
+ string_params['CanonicalizedHeaders']
+ string_params['CanonicalizedResource'])
signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
headers = {
'x-ms-version' : api_version,
'x-ms-date' : request_time,
'x-ms-blob-type': 'BlockBlob',
'Content-Length': '11',
'Content-Type': "text/plain; charset=UTF-8",
'Authorization' : ('SharedKey ' + storage_account_name + ':' + signed_string)
}
url = ('https://' + storage_account_name + '.blob.core.windows.net/'+container_name+'/fname')
r = requests.put(url, headers = headers,data='hello world')
print(r.status_code)
print('\n\n'+r.text)
That's the return error message I got not matter what:这就是我得到的返回错误消息,不管怎样:
<?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:cbf12c65-c01e-00fc-1069-3a41a7000000
Time:2020-06-04T12:11:03.4295368Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'c9n6EKq9p6skUs17qGv/bW0yGRGjMzMrP7bgDwjRABg=' is not the same as any computed signature. Server used following string to sign: 'PUT
11
text/plain; charset=UTF-8
x-ms-blob-type:BlockBlob
x-ms-date:Thu, 04 Jun 2020 12:11:02 GMT
x-ms-version:2015-02-21
/<mystorageaccount>/test/fname'.</AuthenticationErrorDetail></Error>
Can someone pls help me understand what I missing here?有人可以帮助我了解我在这里缺少什么吗?
You need to include text/plain; charset=UTF-8
您需要包含
text/plain; charset=UTF-8
text/plain; charset=UTF-8
for Content-Type
and 11
for Content-Length
in string_params
. text/plain; charset=UTF-8
用于Content-Type
和11
用于string_params
中的Content-Length
。 So your revised code ( string_params
variable only) would be something like:因此,您修改后的代码(
string_params
变量)将类似于:
string_params = {
'verb': 'PUT',
'Content-Encoding': '',
'Content-Language': '',
'Content-Length': '11',
'Content-MD5': '',
'Content-Type': 'text/plain; charset=UTF-8',
'Date': '',
'If-Modified-Since': '',
'If-Match': '',
'If-None-Match': '',
'If-Unmodified-Since': '',
'Range': '',
'CanonicalizedHeaders': 'x-ms-blob-type:BlockBlob' + '\nx-ms-date:' + request_time + '\nx-ms-version:' + api_version,
'CanonicalizedResource': '/' + storage_account_name +'/'+container_name+ '/' +'fname'
}
Rest of your code looks fine.您的代码的 Rest 看起来不错。
UPDATE更新
You're missing a new line character at the end of CanonicalizedHeaders
.您在
CanonicalizedHeaders
末尾缺少一个换行符。 So your string_params
will be like:所以你的
string_params
会像:
string_params = {
'verb': 'PUT',
'Content-Encoding': '',
'Content-Language': '',
'Content-Length': '11',
'Content-MD5': '',
'Content-Type': 'text/plain; charset=UTF-8',
'Date': '',
'If-Modified-Since': '',
'If-Match': '',
'If-None-Match': '',
'If-Unmodified-Since': '',
'Range': '',
'CanonicalizedHeaders': 'x-ms-blob-type:BlockBlob' + '\nx-ms-date:' + request_time + '\nx-ms-version:' + api_version + '\n',
'CanonicalizedResource': '/' + storage_account_name +'/'+container_name+ '/' +'fname'
}
Here is a simpler version of the code with more code reuse:这是一个更简单的代码版本,具有更多的代码重用:
def generate_key(verb, headers, content_type, storage_account_key, canonicalized_resource):
string_to_sign = (verb + '\n'
+ '\n' # Content-MD5
+ content_type+ '\n'
+ '\n' #Date
+ "\n".join([k + ":" + v for k,v in headers.items()]) + '\n'
+ canonicalized_resource)
return base64.b64encode(
hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'),
digestmod=hashlib.sha256).digest()).decode()
def request_with_headers(verb, storage_account_name, storage_account_key, container_name, blob_name, data = None):
api_version = '2018-11-09'
request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
headers = {"x-ms-blob-type": "BlockBlob", "x-ms-date": request_time, "x-ms-version": api_version}
canonicalized_resource = '/' + storage_account_name + '/' + container_name + '/' + blob_name
content_type = "text/plain; charset=UTF-8"
sas_token = generate_key(verb, headers, content_type, storage_account_key, canonicalized_resource)
headers = dict(headers, **{"Content-Type": content_type, "Authorization": "SharedKeyLite %s:%s" % (storage_account_name, sas_token)})
url = "https://%s.blob.core.windows.net/%s/%s" % (storage_account_name, container_name, blob_name)
return requests.request(verb, url, headers=headers, data = data)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.