摘要:本文就将帶您了解OBS的兩種常見的鑒權方式——Header攜帶簽名和URL攜帶簽名。
OBS提供了REST(Representational State Transfer)風格API,支援您通過HTTP/HTTPS請求調用。在調用OBS的API前,需要了解OBS的鑒權認證方式。本文就将帶您了解OBS的兩種常見的鑒權方式——Header攜帶簽名和URL攜帶簽名。
1、在Header中攜帶簽名計算
官網連結:https://support.huaweicloud.com/api-obs/obs_04_0010.html
1.1、簽名的計算原理和計算方法
原理圖示
計算方法
(1).構造請求字元串(StringToSign)。
請求字元串的構造方法如下:
StringToSign =
HTTP-Verb + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
CanonicalizedHeaders + CanonicalizedResource
(2).對第一步的結果進行UTF-8編碼。
(3).使用SK對第二步的結果進行HMAC-SHA1簽名計算。
(4).對第三步的結果進行Base64編碼,得到簽名。
簽名如以下形式(28位長度的BASE64編碼的字元串):
JONydLd9zpf+Eu3IYiUjNmukHN0=
計算示例
例:需要擷取桶”obs-test”下的對象log.conf的對象ACL,如何構造請求并計算簽名?
1、首先明确StringToSign的各字段:
請求方法:GET;
請求MD5:空
Content-Type:空
請求時間:Tue, 28 Jul 2020 06:29:47 GMT(即中原標準時間2020年7月28日14:29:47)
自定義頭域(CanonicalizedHeaders):空
規範化資源(CanonicalizedResource):/obs-test/log.conf?acl
2、構造請求字元串StringToSign如下:
StringToSign = ‘’’GET
Tue, 28 Jul 2020 06:29:47 GMT
/obs-test/log.conf?acl’’’
3、根據簽名算法,将StringToSign進行HMAC-SHA1計算後進行BASE64編碼獲得簽名結果:xYlcrwT9jSaCtY0OnBE01OBR+aA=
1.2、簽名計算的實作方式
以Python計算簽名代碼為例,供參考:
import hashlib
import hmac
import binascii
from datetime import datetime
# 驗證資訊
AK = '您的access_key_id'
SK = '您的secret_access_key_id'
# 指定HTTP方法,可選GET/PUT/DELETE/POST/OPTIONS
httpMethod = "GET"
# 指定請求的Header:Content-Type和Content-MD5
contentType = ""
conten**5 = ""
# 使用datetime庫生成時間,如果需要自定義請求時間請保持格式一緻
date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
# 填寫canonicalizedHeaders
# canonicalizedHeaders = "x-obs-acl:public-read"
# canonicalizedHeaders = "x-obs-acl:public-read\n"+'x-obs-storage-class:WARM\n'
canonicalizedHeaders = ""
# 填寫CanonicalizedResource
# CanonicalizedResource = "/BucketName/ObjectName"
# CanonicalizedResource = "/BucketName/ObjectName?acl"
# CanonicalizedResource = "/"
CanonicalizedResource = "/BucketName/"
# 生成StringToSign
canonical_string = httpMethod + "\n" + conten**5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedHeaders + CanonicalizedResource
# 計算簽名并進行BASE64編碼
hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1)
encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8')
# 列印StringToSign以便出現問題時進行驗證
print(canonical_string)
# 列印簽名
print(encode_canonical)
C語言簽名算法示例:
請參考https://obs-community.obs.cn-north-1.myhuaweicloud.com/sign/signature_c.zip,下載下傳C語言簽名計算代碼樣例,其中:
計算簽名的接口包含在sign.h頭檔案中。
計算簽名的示例代碼在main.c檔案中。
可視化簽名計算工具:
您也可以通過OBS提供的可視化簽名計算工具來計算簽名。
工具連結:
https://obs-community.obs.cn-north-1.myhuaweicloud.com/sign/header_signature.html
說明:
1. canonicalizedHeaders:表示HTTP請求頭域中的OBS請求頭字段,即以“x-obs-”作為前辍的頭域,如“x-obs-date,x-obs-acl,x-obs-meta-*”;
a.請求頭字段中關鍵字的的所有字元要轉為小寫,需要添加多個字段時,要将所有字段按照關鍵字的字典序從小到大進行排序;
b.在添加請求頭字段時,如果有重名的字段,則需要進行合并。如:x-obs-meta-name:name1和x-obs-meta-name:name2,則需要先将重名字段的值(這裡是name1和name2)以逗号分隔,合并成x-obs-meta-name:name1,name2;
c.頭域中的請求頭字段中的關鍵字不允許含有非ASCII碼或不可識别字元;請求頭字段中的值也不建議使用非ASCII碼或不可識别字元,如果一定要使用非ASCII碼或不可識别字元,需要用戶端自行做編解碼處理,可以采用URL編碼或者Base64編碼,服務端不會做解碼處理;
d.當請求頭字段中含有無意義空格或table鍵時,需要摒棄。例如:x-obs-meta-name: name(name前帶有一個無意義空格),需要轉換為:x-obs-meta-name:name;
e.每一個請求頭字段最後都需要另起新行。
2. canonicalizedResource表示HTTP請求所指定的OBS資源,構造方式如下:
<桶名+對象名>+[子資源] …
a.通過桶綁定的自定義域名通路OBS,桶名由自定義域名表示,則為"/obs.ccc.com/object",其中“obs.ccc.com”為桶綁定的自定義域名。如果沒有對象名,如列舉桶,則為"/obs.ccc.com/";
b.不是通過桶綁定的自定義域名通路OBS的場景,則為"/bucket/object",如果沒有對象名,如列舉桶,則為"/bucket/"。如果桶名也沒有,則為“/”;
c.如果有子資源,則将子資源添加進來,例如?acl,?logging。
3. 如需要使用臨時AK/SK+SecurityToken的方式計算簽名,計算簽名的方法保持一緻,但需要在頭域中添加“x-obs-security-token:…”字段。
4.計算Content-MD5的方法見文末的說明。
5.其他語言計算簽名的代碼可詳見對應語言的SDK,詳見:
https://support.huaweicloud.com/sdkreference-obs/obs_02_0001.html
1.3、常見問題
1.通路OBS時報錯:Signature Does Not Match
簽名不比對的情況主要有以下兩種可能:
a.您沒有使用正确的AK/SK,您可以檢查您計算簽名使用的SK和發送請求時所攜帶的AK是否正确且比對;
b.您計算簽名時構造的StringToSign和服務端根據接收到的HTTP請求所計算的StringToSign不比對,您可以檢查服務端傳回的StringToSign,并與本地計算簽名所使用的StringToSign進行對比。
如下圖是服務端傳回的由接收到HTTP請求所還原的StringToSign,您可以通過對比您本地的StringToSign和您發送到服務端的HTTP請求,來分析您簽名計算失敗的原因。
2.通路OBS時報錯:Request has expired
此類情況請您檢查您攜帶的Date是否正确,為保證請求的時效性,您所攜帶的Date頭域必須與服務端的時間相差在15分鐘以内(服務端為UTC時間),如您攜帶了x-obs-date頭域,需檢查x-obs-date的時間是否與服務端時間相差15分鐘以内。
2、在URL中攜帶簽名
OBS服務支援使用者構造一個特定操作的URL,這個URL中會包含使用者AK、簽名、有效期、資源等資訊,任何拿到這個URL的人均可執行這個操作,OBS服務收到這個請求後認為該請求就是簽發URL使用者自己在執行操作。例如構造一個攜帶簽名資訊的下載下傳對象的URL,拿到相應URL的人能下載下傳這個對象,但該URL隻在Expires指定的失效時間内有效。URL中攜帶簽名主要用于在不提供給其他人Secret Access Key的情況下,讓其他人能用預簽發的URL來進行身份認證,并執行預定義的操作。
官網連結https://support.huaweicloud.com/api-obs/obs_04_0011.html
2.1、簽名的計算原理和計算方法
1.構造請求字元串(StringToSign)。
2.對第一步的結果進行UTF-8編碼。
3.使用SK對第二步的結果進行HMAC-SHA1簽名計算。
4.對第三步的結果進行Base64編碼,得到簽名。
JONydLd9zpf+Eu3IYiUjNmukHN0=
URL中攜帶的簽名計算方法同Header中攜帶簽名的簽名計算方法,但是需要将Date更換為UNIX時間戳。
攜帶簽名的URL形式如下:
obs-ycytest.obs.cn-north-1.myhuaweicloud.com/?AccessKeyId=YN97UCJEKF2ALJ44AHAN&Expires=1575452568&Signature=0wG/GF7XgmOatCFhwHJh0J6NrtQ=
其對應的StringToSign為
GET
1575452568
/obs-ycytest/
URL中攜帶的參數具體含義見下表:
請求方法:GET;
請求MD5:空
Content-Type:空
請求時間:1595918661(即中原標準時間2020年7月28日14:44:21)
自定義頭域(CanonicalizedHeaders):空
規範化資源(CanonicalizedResource):/obs-test/log.conf?acl
StringToSign = ‘’’GET
1595918661
/obs-test/log.conf?acl’’’
3、根據簽名算法,将StringToSign進行HMAC-SHA1計算後進行BASE64編碼獲得簽名結果:lLcYw1fFMJv5m+MS0XenNrqJlag=
根據計算的結果,将URL拼接起來即可生成攜帶簽名的URL如下:
obs-test.obs.myhuaweicloud.com/log.conf?AccessKeyId=xxx&acl&Expires=1595918661&Signature= lLcYw1fFMJv5m+MS0XenNrqJlag=
2.2、簽名計算的實作方式
在URL中攜帶簽名時,隻需将Date替換為UNIX時間戳即可計算對應的簽名,是以對應的代碼不再贅述。
如需要使用臨時AK/SK+SecurityToken的方式計算簽名,計算簽名的方法保持一緻,但需要在對應的CanonicalizedResource中添加“?x-obs-security-token=…”字段,且計算得到的簽名必須要進行URL編碼。使用臨時AK/SK+SecurityToken計算簽名的代碼如下:
import hashlib
import hmac
import binascii
import urllib.request
AK = 'Input Your AccessKeyId'
SK = 'Input Your SecretKeyId'
Token = 'Input Your SecurityToken'
httpMethod = "GET"
contentType = ""
Conten**5 = ''
date = '1594972984'
canonicalizedHeaders = ''
CanonicalizedResource = "/messageflow/flowengine.tar.gz" + "?x-obs-security-token=" + Token
canonical_string = httpMethod + "\n" + Conten**5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedHeaders + CanonicalizedResource
hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1)
encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8')
url= 'messageflow.obs.myhuaweicloud.com/flowengine.tar.gz?x-obs-security-token={}&Expires={}&AccessKeyId={}&Signature={}'.format(Token, date, AK, urllib.request.quote(encode_canonical))
print(url)
1.在計算簽名時,Date表示的是一個UNIX時間戳;
2.如果想要在浏覽器中使用URL中攜帶簽名生成的預定于URL,則計算簽名時不要使用“Content-MD5”、“Content-Type”、“CanonicalizedHeaders”計算簽名,否則浏覽器不能攜帶這些參數,請求發送到服務端之後,會提示簽名錯誤。
3、Content-MD5的計算方式
3.1、Content-MD5的計算方法
以消息内容“0123456789”為例,以下詳細說明計算該字元串的Content-MD5的方法。
1.先計算MD5加密的二進制數組(128位)。
2.對這個二進制數組進行base64編碼(而不是對32位字元串編碼)。
以Python為例:
>>> import base64,hashlib
>>> hash = hashlib.md5()
>>> hash.update("0123456789".encode(‘utf-8’))
>>> base64.b64encode(hash.digest())
'eB5eJF1ptWaXm4bijSPyxw=='
注:hash.digest(),計算出二進制數組(128位)。
>>> hash.digest()
'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7'
3.2、Content-MD5計算的實作
以Python計算檔案MD5代碼為例,供參考:
import os
import base64
import hashlib
def md5_file_encode_by_size_offset(file_path=None, size=None, offset=None, chuckSize=None):
if file_path is not None and size is not None and offset is not None:
m = hashlib.md5()
with open(file_path, 'rb') as fp:
CHUNKSIZE = 65536 if chuckSize is None else chuckSize
fp.seek(offset)
read_count = 0
while read_count < size:
read_size = CHUNKSIZE if size - read_count >= CHUNKSIZE else size - read_count
data = fp.read(read_size)
read_count_once = len(data)
if read_count_once <= 0:
break
m.update(data)
read_count += read_count_once
return base64.b64encode(m.digest()).decode()
file_path = r'Input Your File Path'
size = os.path.getsize(file_path)
Conten**5 = md5_file_encode_by_size_offset(file_path=file_path, size=size, offset=0)
print(Conten**5)
3.3、常見問題
常見錯誤是直接對計算出的32位字元串進行base64編碼。
# hash.hexdigest(),計算得到可見的32位字元串編碼。
>>> import base64,hashlib
>>> hash = hashlib.md5()
>>> hash.update("0123456789".encode(‘utf-8’))
>>> hash.hexdigest()
'781e5e245d69b566979b86e28d23f2c7'
# 錯誤的MD5值進行base64編碼後的結果:
>>> base64.b64encode(hash.hexdigest())
'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='
點選關注,第一時間了解華為雲新鮮技術~