日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AWS s3 V4签名算法

發布時間:2024/2/28 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AWS s3 V4签名算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原創,轉載請注明:http://www.jianshu.com/p/a6a02309190f

一、開篇說明:
以下思考方向,是以Android端為出發點(IOS同理)
AWS:Amazon Web Services (亞馬遜云服務)
AWS s3 API文檔:https://aws.amazon.com/cn/documentation/s3/

Minio :(具體的解釋自行百度吧)一個基于 golang 語言開發的 AWS S3 存儲協議的開源實現,并附帶 web ui 界面,可以通過 Minio 搭建私人的兼容 AWS S3 協議的存儲服務器。

二、需求分析
項目需求:最近公司需要搭建一個文件服務器,讓移動端(Android、ios)用來存儲圖片等文件。這個文件服務器后臺使用minio搭建的。由于minio是基于AWS S3 存儲協議,所以我們移動端也需要實現相同的協議來上傳。移動端,我們確定了三種可行方案(方案優劣僅是基于對APK打包大小的影響程度來確定的):

方案一:基于AWS S3 存儲協議自己實現文件上傳(最佳方案,最后項目引入文件最小----大約100K,不影響apk大小)
方案二:使用AWS SDK 實現文件上傳(中間方案,需要引入項目的jar包1.5M文件略大)
方案三:使用minio SDK 實現文件上傳(最差方案,需要引入6M jar包)
三、代碼實現
由于項目需求不同,供大家自行選擇,我將這三種方案實現一一說明。

方案三:
demo下載:https://github.com/Nergal1/minio-demo

1.Android端引入minio SDK jar包會和原生的發生沖突,會報一些安全錯誤。
引入時,去除沖突的包,com.fasterxml.jackson.core和com.google.code.findbugs:

dependencies {compile ('io.minio:minio:3.0.4'){excludegroup:'com.fasterxml.jackson.core'excludegroup:'com.google.code.findbugs'} }


2.上傳代碼:

/\*上傳圖片 bucketName:服務端存儲文件夾,必須先創建 objectName:服務端存儲文件名 inputStream:上傳文件流 \*/ minioClient.putObject(bucketName,objectName,inputStream,inputStream.available(),"application/octet-stream");


提醒:別忘了開啟網絡權限
3.簡易源碼流程圖,數字代表行號:

minio上傳源碼簡易流程圖
方案二:
demo下載:https://github.com/Nergal1/AWS-S3-demo

1.由于AWS SDK源碼中是開啟Service,然后創建線程池實現異步上傳、下載功能。
清單文件要注冊service:

<service android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService" android:enabled="true"/>


權限:

android.permission.INTERNET android.permission.ACCESS_NETWORK_STATE android.permission.READ_EXTERNAL_STORAGE android.permission.WRITE_EXTERNAL_STORAGE Android 6.0+文件讀寫權限需要代碼中實時獲取,demo中未作兼容。如有文件問題,請自行添加。

2.引入jar包:
aws-android-sdk-core-2.4.2.jar
aws-android-sdk-s3-2.4.2.jar

3.先配置Constants.java中的ENDPOINT、ACCESSKEY、SecretKey、BUCKET_NAME
上傳代碼見UploadActivity.java(下載請自行查看DownloadActivity):

TransferUtility transferUtility= Util.getTransferUtility(this); //上傳 TransferObserver observer =transferUtility.upload(Constants.BUCKET_NAME,file.getName(), file); //設置上傳監聽 observer.setTransferListener(new UploadListener());

?

//監聽類 private class UploadListener implements TransferListener { // Simply updates the UI list when notified. 上傳失敗監聽 @Override public voidonError(intid,Exception e) { Log.e(TAG,"Error during upload: "+ id,e); updateList(); } //上傳進度監聽 @Override public voidonProgressChanged(intid, longbytesCurrent, longbytesTotal) { Log.d(TAG,String.format("onProgressChanged: %d, total: %d, current: %d", id,bytesTotal,bytesCurrent)); updateList(); } //上傳狀態監聽 @Override public voidonStateChanged(intid,TransferState newState) { Log.d(TAG,"onStateChanged: "+ id +", "+ newState);//例如:UploadActivity: onStateChanged: 9, FAILD 失敗狀態 // ? ? ? ? ? ?//根據id 查詢文件路徑 // ? ? ? ? ? ?TransferObserver transferObserver = transferUtility.getTransferById(id); // ? ? ? ? ? ?Log.d(TAG, "文件地址---"+transferObserver.getAbsoluteFilePath()); updateList(); } }


4.源碼簡易流程圖,數字代表行號:

aws sdk上傳源碼簡易流程圖
3.實現原理分析:
實際上AWS S3 存儲協議只不過是添加一些跟服務端協商的請求頭,請求頭的value是用AWS s3 V4簽名算法算出來的。所以,上傳時帶上指定的請求頭,以及合法的簽名算法,其他地方跟普通上傳沒區別。服務端拿到請求頭后,根據合法的簽名算法,計算簽名值,然后跟客戶端請求頭里的簽名進行校驗,成功后,服務端才允許上傳。
首先我們要解決兩個問題:
(1)指定的請求頭有哪些?
首先我們來看一個文件上傳的請求:

--------------------------請求頭-------------------------- PUT /test/IMG_20170519_165644_1.jpg HTTP/1.1 Content-MD5: 6PN5Zj06z+D5UkSG1ZxhNA== x-amz-decoded-content-length: 2566214 x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD Content-Type: image/jpeg X-Amz-Date: 20170522T024116Z User-Agent: aws-sdk-android/2.4.2 Linux/3.10.86-g6be8ceb Dalvik/2.1.0/0 zh_CN TransferService/2.4.2 aws-sdk-retry: 0/0 Accept-Encoding: identity aws-sdk-invocation-id: 148858f7-e319-4578-b9f8-1b220f6af380 Authorization: AWS4-HMAC-SHA256 Credential=1NA5K80UU85NMPK4BPEW/20170522/us-east-1/s3/aws4_request,SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length,Signature=db4e0abd4290730ed6fd27867d2fa342942372b88f1b5ad49b113ab9c77d6cc9 Content-Length: 2568100 Host: www.baidu.com Connection: Keep-Alive

?

--------------------------------------請求體-------------- 20000;chunk-signature=0cfa38451a889b866dbf43907ce3a72ee85f6b176168fb875903e8353366628e 。。。二進制文件流。。。


一大堆請求頭,實際上根據 S3 API 文檔,Authorization請求頭才是必要的
而Authorization的value中SignedHeaders是規定了使用哪些請求頭來計算本次請求的簽名值。
注意:SignedHeaders還規定了請求頭的順序。后面計算簽名流程圖中Canonical Request拼接請求頭的順序與SignedHeaders必須保持一致。
也就是說content-md5;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length這些請求頭計算出來Signature的值。根據S3 API 文檔,SignedHeaders中host;x-amz-content-sha256;x-amz-date是必須存在的。
那為什么本次請求還要加上content-md5,x-amz-decoded-content-length這兩個值?
我們來想想簽名的作用:

  • a.驗證請求身份

ACCESSKEY、SecretKey就是用來驗證身份的,這兩個參數也是計算Authorization的value中Signature的值所必須的。

  • b.防止篡改

SignedHeaders就是用來設置防止篡改的請求頭的,content-md5是防止篡改請求內容(body),x-amz-decoded-content-length防止篡改請求內容長度的。
官方文檔中,SignedHeaders必須的host;x-amz-content-sha256;x-amz-date這幾個也就可以理解了,防止篡改請求地址,請求內容的sha256值,請求時間戳

  • c.防止請求簽名被盜用

根據AWS S3 存儲協議,時間戳(x-amz-date或Date請求頭)15分鐘內有效,沒有權限的用戶t通過截獲已簽名的request,可以篡改SignedHeaders中沒有包含的部分,所以官方建議,簽名所有請求頭和請求體(也就是說SignedHeaders要盡量包含所有),還有最好用Https.

  • 總結:

啰嗦一大堆,必要的請求頭有哪些:Authorization、SignedHeaders中包含的(必須包含的有host;x-amz-content-sha256;x-amz-date),host,x-amz-content-sha256,x-amz-date這些請求頭是服務端校驗簽名必須的。
(2)簽名算法是如何計算的?(即Authorization中的Signature)
有兩種簽名算法:

  • 第一種,單塊傳輸(本人demo中使用的這種方式)

文件內存讀取兩次(一次計算文件sha256時,一次文件上傳時)
單塊上傳請求頭:
x-amz-content-sha256: 32e820d03db121caf97206f8cbcc6202cf25bf59246e8d6b0e8f6e3502d68f66
或:x-amz-content-sha256: UNSIGNED-PAYLOAD(這種是單塊不進行簽名內容的寫法)
a.

單塊上傳簽名計算流程
功能函數說明:
Lowercase():字符串轉成小寫.
Hex():base 16編碼(全部小寫).
SHA256Hash():計算請求體body(上傳文件時,body中只有文件,即計算文件的SHA256)的SHA256,然后base64.
HMAC-SHA256():通過將key使用SHA256計算 HMAC

public static byte[]sumHmac(byte[] key, byte[] data) throwsNoSuchAlgorithmException,InvalidKeyException { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(newSecretKeySpec(key,"HmacSHA256")); mac.update(data); returnmac.doFinal(); }


Trim():去空格.
UriEncode():
a.保持'A'-'Z','a'-'z', '0'-'9', '-', '.', '_', '~'不變
b.空格字符必須轉成"%20" (而不是 "+")
c.byte編譯成“%”后面跟兩位的十六進制(字母大寫)
d.如果文件名(object name)類似“photos/Jan/sample.jpg”,其中包含“/”,不進行轉義。

public static String UriEncode(CharSequence input, boolean encodeSlash) { StringBuilder result = new StringBuilder(); for (int i = 0; i < input.length(); i++) { char ch = input.charAt(i); if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') { result.append(ch); } else if (ch == '/') { result.append(encodeSlash ? "%2F" : ch); } else { result.append(toHexUTF8(ch)); } } return result.toString(); }

?

  • 第二種,多塊傳輸

多塊上傳請求頭:
x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD
把有效荷載(請求body)分成幾塊,固定或可變大小的塊。通過上傳塊,避免讀取整個文件的有效荷載來計算簽名.

  • a.第一塊,計算所有的請求頭的簽名,空body請求
  • b.第二塊,將第一個塊的簽名和有效載荷一起計算簽名
  • c.第n塊,將第n-1塊的簽名和有效載荷一起計算簽名
  • d.最后,發送0 bytes的塊包含第n塊的簽名。

請求頭Authorization中的Signature計算同單塊上傳:

多塊上傳簽名計算流程圖
請求體中塊簽名計算:


請求體中比單塊上傳多了這些


chunk-signature的簽名計算流程圖

終于,說完了,第一次寫這么長,講的有不清楚的多多包涵,有什么問題可以給我留言,也可以發我郵箱18514689920@163.com.
---------------------?
作者:nergal_?
來源:CSDN?
原文:https://blog.csdn.net/e491288767/article/details/72819606?
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

總結

以上是生活随笔為你收集整理的AWS s3 V4签名算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。