摘要:OBS提供了REST(Representational State Transfer)格调API,反对您通过HTTP/HTTPS申请调用。本文将带你理解OBS API鉴权实现的宝典秘籍。
OBS提供了REST(Representational State Transfer)格调API,反对您通过HTTP/HTTPS申请调用。在调用OBS的API前,须要理解OBS的鉴权认证形式。
签名计算篇
本文就将带您理解OBS的两种常见的鉴权形式——Header携带签名和URL携带签名。
1、在Header中携带签名计算
官网链接:https://support.huaweicloud.c...
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计算签名代码为例,供参考:
1. import hashlib 2. import hmac 3. import binascii 4. from datetime import datetime 5. 6. # 验证信息 7. AK = '您的access_key_id' 8. SK = '您的secret_access_key_id' 9. 10. # 指定HTTP办法,可选GET/PUT/DELETE/POST/OPTIONS 11. httpMethod = "GET" 12. 13. # 指定申请的Header:Content-Type和Content-MD5 14. contentType = "" 15. conten**5 = "" 16. 17. # 应用datetime库生成工夫,如果须要自定义申请工夫请放弃格局统一 18. date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') 19. 20. # 填写canonicalizedHeaders 21. # canonicalizedHeaders = "x-obs-acl:public-read" 22. # canonicalizedHeaders = "x-obs-acl:public-readn"+'x-obs-storage-class:WARMn' 23. canonicalizedHeaders = "" 24. 25. # 填写CanonicalizedResource 26. # CanonicalizedResource = "/BucketName/ObjectName" 27. # CanonicalizedResource = "/BucketName/ObjectName?acl" 28. # CanonicalizedResource = "/"29. CanonicalizedResource = "/BucketName/" 30. 31. # 生成StringToSign 32. canonical_string = httpMethod + "n" + conten**5 + "n" + contentType + "n" + date + "n" + canonicalizedHeaders + CanonicalizedResource 33. 34. # 计算签名并进行BASE64编码 35. hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1) 36. encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8') 37. 38. # 打印StringToSign以便呈现问题时进行验证 39. print(canonical_string) 40. 41. # 打印签名 42. print(encode_canonical)
C语言签名算法示例:
请参考https://obs-community.obs.cn-...,下载C语言签名计算代码样例,其中:
计算签名的接口蕴含在sign.h头文件中。
计算签名的示例代码在main.c文件中。
可视化签名计算工具:
您也能够通过OBS提供的可视化签名计算工具来计算签名。
工具链接:
https://obs-community.obs.cn-...
阐明:
- 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.每一个申请头字段最初都须要另起新行。
- canonicalizedResource示意HTTP申请所指定的OBS资源,结构形式如下:
<桶名+对象名>+[子资源] …
a.通过桶绑定的自定义域名拜访OBS,桶名由自定义域名示意,则为"/http://obs.ccc.com/object",其中“obs.ccc.com”为桶绑定的自定义域名。如果没有对象名,如列举桶,则为"/http://obs.ccc.com/";
b.不是通过桶绑定的自定义域名拜访OBS的场景,则为"/bucket/object",如果没有对象名,如列举桶,则为"/bucket/"。如果桶名也没有,则为“/”;
c.如果有子资源,则将子资源增加进来,例如?acl,?logging。
- 如须要应用长期AK/SK+SecurityToken的形式计算签名,计算签名的办法保持一致,但须要在头域中增加“x-obs-security-token:…”字段。
4.计算Content-MD5的办法见文末的阐明。
5.其余语言计算签名的代码可详见对应语言的SDK,详见:
https://support.huaweicloud.c...
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)。
申请字符串的构造方法如下:
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=
URL中携带的签名计算方法同Header中携带签名的签名计算方法,然而须要将Date更换为UNIX工夫戳。
携带签名的URL模式如下:
http://obs-ycytest.obs.cn-nor...
其对应的StringToSign为
GET
1575452568
/obs-ycytest/
URL中携带的参数具体含意见下表:
计算示例
例:须要获取桶”obs-test”下的对象log.conf的对象ACL,如何结构申请并计算签名?
1、首先明确StringToSign的各字段:
申请办法:GET;
申请MD5:空
Content-Type:空
申请工夫:1595918661(即北京工夫2020年7月28日14:44:21)
自定义头域(CanonicalizedHeaders):空
规范化资源(CanonicalizedResource):/obs-test/log.conf?acl
2、结构申请字符串StringToSign如下:
StringToSign = ‘’’GET
1595918661
/obs-test/log.conf?acl’’’
3、依据签名算法,将StringToSign进行HMAC-SHA1计算后进行BASE64编码取得签名后果:lLcYw1fFMJv5m+MS0XenNrqJlag=
依据计算的后果,将URL拼接起来即可生成携带签名的URL如下:
http://obs-test.obs.myhuaweic...
2.2、签名计算的实现形式
在URL中携带签名时,只需将Date替换为UNIX工夫戳即可计算对应的签名,因而对应的代码不再赘述。
如须要应用长期AK/SK+SecurityToken的形式计算签名,计算签名的办法保持一致,但须要在对应的CanonicalizedResource中增加“?x-obs-security-token=…”字段,且计算失去的签名必须要进行URL编码。应用长期AK/SK+SecurityToken计算签名的代码如下:
1. import hashlib 2. import hmac 3. import binascii 4. import urllib.request 5. 6. AK = 'Input Your AccessKeyId' 7. SK = 'Input Your SecretKeyId' 8. Token = 'Input Your SecurityToken' 9. 10. httpMethod = "GET" 11. contentType = "" 12. Conten**5 = '' 13. date = '1594972984' 14. canonicalizedHeaders = '' 15. CanonicalizedResource = "/messageflow/flowengine.tar.gz" + "?x-obs-security-token=" + Token 16. canonical_string = httpMethod + "n" + Conten**5 + "n" + contentType + "n" + date + "n" + canonicalizedHeaders + CanonicalizedResource 17. hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1) 18. encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8') 19. 20. url= 'messageflow.obs.myhuaweicloud.com/flowengine.tar.gz?x-obs-security-token={}&Expires={}&AccessKeyId={}&Signature={}'.format(Token, date, AK, urllib.request.quote(encode_canonical)) 21. 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,hashlibhash = hashlib.md5()
hash.update("0123456789".encode(‘utf-8’))
base64.b64encode(hash.digest())
'eB5eJF1ptWaXm4bijSPyxw=='
注:hash.digest(),计算出二进制数组(128位)。
hash.digest()
'xx1e^$]ixb5fx97x9bx86xe2x8d#xf2xc7'
3.2、Content-MD5计算的实现
以Python计算文件MD5代码为例,供参考:
1. import os 2. import base64 3. import hashlib 4. 5. 6. def md5_file_encode_by_size_offset(file_path=None, size=None, offset=None, chuckSize=None): 7. if file_path is not None and size is not None and offset is not None: 8. m = hashlib.md5() 9. with open(file_path, 'rb') as fp: 10. CHUNKSIZE = 65536 if chuckSize is None else chuckSize 11. fp.seek(offset) 12. read_count = 0 13. while read_count < size: 14. read_size = CHUNKSIZE if size - read_count >= CHUNKSIZE else size - read_count 15. data = fp.read(read_size) 16. read_count_once = len(data) 17. if read_count_once <= 0: 18. break 19. m.update(data) 20. read_count += read_count_once 21. return base64.b64encode(m.digest()).decode() 22. 23. 24. file_path = r'Input Your File Path' 25. size = os.path.getsize(file_path) 26. Conten**5 = md5_file_encode_by_size_offset(file_path=file_path, size=size, offset=0) 27. print(Conten**5)
3.3、常见问题
常见谬误是间接对计算出的32位字符串进行base64编码。
hash.hexdigest(),计算失去可见的32位字符串编码。
import base64,hashlibhash = hashlib.md5()
hash.update("0123456789".encode(‘utf-8’))
hash.hexdigest()
'781e5e245d69b566979b86e28d23f2c7'
谬误的MD5值进行base64编码后的后果:
base64.b64encode(hash.hexdigest())
'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='
POST签名计算
OBS服务反对基于浏览器的POST上传对象申请,此类申请的签名信息通过表单的形式上传。POST上传对象的流程次要如下:
首先,创立一个安全策略,指定申请中须要满足的条件,比方:桶名、对象名前缀;
而后,创立一个基于此策略的签名,须要签名的申请表单中必须蕴含无效的signature和policy;
最初,创立一个表单将对象上传到桶中。
1、基于浏览器上传的表单中携带签名
官网链接:https://support.huaweicloud.c...
1.1、签名的计算原理和计算方法
原理图示
计算方法
1.结构申请Policy:
例如一个最简略的申请Policy如下:
Policy = { "expiration": "2020-12-21T12:00:00.000Z", "conditions": [ { "bucket": "obs-test" }, [ "eq", "$key", "post.txt" ], ]}
2.对申请Policy进行UTF-8编码。
3.对第二步的后果进行Base64编码。
4.应用SK对第三步的后果进行HMAC-SHA1签名计算。
5.对第四步的后果进行Base64编码,失去签名。
签名如以下模式(28位长度的BASE64编码的字符串):
CVs7GTY6n8Gdhc74Gj+QhpbxtT4=
即:StringToSign = Base64( UTF-8-Encoding-Of( policy ) )
Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, StringToSign ) )
计算示例
例:须要通过浏览器表单上传对象”post.txt”到桶”obs-test”下,同时设置对象ACL为公共读,如何结构申请并计算签名?
1、首先结构申请Policy:
设置申请过期工夫:2020-12-21T12:00:00.000Z
桶名:obs-test
对象ACL:public-read
匹配条件:对象名=post.txt
2、结构Policy如下:
{ "expiration": "2020-12-21T12:00:00.000Z", "conditions": [ { "bucket": "obs-test" }, { "x-obs-acl": "public-read" }, [ "eq", "$key", "post.txt" ], ]}
3、依据签名算法,将Policy进行UTF-8编码后再进行BASE64编码,再进行HMAC-SHA1计算后取得签名后果:odouyqpyXcYlKQz7G1/EaUNfJUE=
1.2、签名计算的实现形式
以Python计算签名代码为例,供参考:
1. import hashlib 2. import hmac 3. import binascii 4. 5. # 验证信息 6. SK = '您的secret_access_key_id' 7. 8. # Policy 9. canonical_string = '''''{ 10. "expiration": "2020-12-21T12:00:00.000Z", 11. "conditions": [ 12. { 13. "bucket": "obs-test" 14. }, 15. { 16. "x-obs-acl": "public-read" 17. }, 18. [ 19. "eq", 20. "$key", 21. "post.txt" 22. ], 23. ] 24. }''' 25. 26. policybase64 = binascii.b2a_base64(canonical_string.encode('utf-8')) 27. policybase64 = policybase64[:-1].decode('UTF-8') 28. # Policy的Base64编码 29. print(policybase64) 30. hashed = hmac.new(SK.encode('UTF-8'), policybase64.encode('UTF-8'), hashlib.sha1) 31. encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8') 32. # 签名 33. print(encode_canonical)
阐明:
- policy应用json格局,conditions能够反对 { } 和 [ ] 两种形式,{ }中蕴含表单元素的key和value两项,以冒号分隔;[ ]中蕴含条件类型、key、value三项,以逗号分隔,元素key之前应用$字符示意变量;
2.下表内的字符都必须进行本义:
1.3、基于浏览器表单上传的Policy与其余形式的StringToSign的异同
基于浏览器表单上传时,匹配条件能够设置为“Starts-With”,即前缀匹配而非准确匹配,因而在上传时实用于更广的场景。
OBS API实战篇
OBS提供了REST(Representational State Transfer)格调API,反对您通过HTTP/HTTPS申请调用。
通过前述的签名计算方法,想必大家对OBS的API鉴权形式曾经有所理解,下文将通过Postman、cURL、编码等办法对OBS的API进行实战调用。
1、OBS反对的API列表
详见官网链接:https://support.huaweicloud.c...
2、结构申请
本节次要介绍OBS RESTful 申请的形成
2.1、申请URI
OBS依据桶和对象以及所对应的子资源参数来确定具体的URI,当须要进行资源操作时,能够应用这个URI地址。
URI的个别格局为(方括号内为可选项):
protocol://[bucket.]domain:port[?param]
URI中参数的具体含意如下:
2.2、申请办法
HTTP办法(也称为操作或动词),它通知服务你正在申请什么类型的操作。
华为云对象存储反对以下的REST申请办法:
2.3、申请音讯头
申请音讯头是可选的附加申请头字段,如指定的URI和HTTP办法所要求的字段。以下是OBS的公共申请音讯头:
2.4、申请音讯体(可选)
申请音讯体通常以结构化格局(如JSON或XML)收回,与申请音讯头中Content-type对应,传递除申请音讯头之外的内容。若申请音讯体中参数反对中文,则中文字符必须为UTF-8编码。
每个接口的申请音讯体内容不同,也并不是每个接口都须要有申请音讯体(或者说音讯体为空),GET、DELETE操作类型的接口就不须要音讯体,音讯体具体内容须要依据具体接口而定。
3、发动申请
本文以列举桶内对象为例,阐明各种客户端发动申请调用OBS API的流程。
3.1、结构申请
1、依照上述2.1构建申请URI,本例中的URI即为“bucketname.obs.cn-north-4.myhuaweicloud.com”;
2.依照上述2.2抉择对应的申请办法,本例应用“GET”申请办法;
3.依照2.3抉择对应的申请音讯头,因为本例的申请为GET申请,因而Content-Type、Content-Length、Content-MD5都设置为空字符串;
其中“Authorization”申请头中的签名须要依据前文所述的签名计算方法进行计算:
StringToSign=GET
Thu, 03 Sep 2020 01:57:08 GMT
/bucketname/
将其进行加密并进行编码后,取得Authorization头域为:OBS Y5IBJTPVZBXYXVLKVOSZ:L0h7P/XDJltLkT/arekZy3Ysh68=
4.传入对应的申请音讯体,本例中不波及。
3.2、应用PostMan发动申请
Postman是一种网页调试与发送网页http申请的chrome插件。咱们能够用来很不便的模仿get或者post或者其余形式的申请来调试接口。
因为Postman具备可视化的操作界面,因而调试接口过程不再赘述。
注意事项:
当在申请中不手动指定“Content-Type”等头域时,Postman会主动生成头域,可能会导致签名不匹配的状况,可通过点击红框中的按钮将暗藏头域显示以便定位此类问题;
3.3、应用cURL发动申请
cURL是利用URL语法在命令行形式下工作的文件传输工具。利用cURL能够调试OBS提供的接口。在应用curl调试OBS API时,须要用到以下的语法:
-H HTTP申请头
-X HTTP办法
调用OBS提供的列举对象接口时,在Linux终端下执行以下命令:
curl -X GET https://bucketname.obs.cn-nor... -H "Content-Type:" -H "Authorization:OBS Y5IBJTPVZBXYXVLKVOSZ:*" -H "Date:Tue, 25 Aug 2020 03:16:39 GMT" –kv
即可获取到接口返回的信息。
注意事项:
curl命令所携带的 –k参数容许curl应用非平安的ssl连贯并且传输数据(证书不受信),而-v参数能输入更具体的参数便于debug。
3.4、应用HTTP申请库发动申请
通过编码发动申请,以Python常见的HTTP申请库requests库为例,代码如下:(示例代码中已集成签名计算)
1. import hashlib 2. import hmac 3. import binascii 4. from datetime import datetime 5. import requests 6. import time 7. 8. AK = "Input Your Access Key Id" 9. SK = "Input Your Secret Access Key Id" 10. 11. 12. time = time.time() 13. time = int(time) 14. time = str(time) 15. 16. # 计算签名 17. httpMethod = 'GET' 18. contentType = '' 19. Conten**5 = '' 20. date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') 21. canonicalizedHeaders = '' 22. canonicalizedResource = '/obs-yuchenyu/' 23. canonical_string = httpMethod + "n" + Conten**5 + "n" + contentType + "n" + date + "n" + canonicalizedHeaders + canonicalizedResource 24. hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1) 25. encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8') 26. 27. url = 'https://obs-yuchenyu.obs.cn-north-4.myhuaweicloud.com/' 28. 29. # 生成申请头 30. headers = { 31. 'Date': date, 32. 'Authorization': 'OBS {}:{}'.format(AK, encode_canonical), 33. 'Content-Type': '', 34. 'Content-MD5': '' 35. } 36. 37. 38. # 发送申请 39. resp = requests.get(url, headers=headers, verify=False) 40. print(resp.status_code) 41. print(resp.headers) 42. print(resp.content.decode('utf-8')) 返回后果如下:"C:Program FilesPython37python.exe" "D:/OBS PythonSDK/OBS_API.py"200{'via': 'proxy A', 'Date': 'Tue, 25 Aug 2020 03:25:59 GMT', 'Server': 'OBS', 'Connection': 'Keep-Alive', 'x-obs-id-2': '32AAAQAAEAABAAAQAAEAABAAAQAAEAABCTDP5fqiYrOrqBlcJ91P0KqhCGTp+5Pl', 'Content-Type': 'application/xml', 'Content-Length': '28217', 'x-obs-request-id': '0000017423A6A7AA44CB43873F3DBCD6', 'x-obs-bucket-location': 'cn-north-4'}<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ListBucketResult xmlns="http://obs.myhwclouds.com/doc/2015-06-30/">……Process finished with exit code 0
**[点击关注,第一工夫理解华为云陈腐技术~](https://bbs.huaweicloud.com/b...
)**