目標
使用 PHP 創建 COS 接口所需要的請求簽名
步驟
按照官方示例(也許是我笨,我怎么讀都覺得官方文檔結構費勁,示例細節互相不挨著,容易引起歧義),請求簽名應用在需要身份校驗的場景,即非公有讀權限時。否則在請求API接口時,就必須攜帶簽名作為請求頭的一部分傳遞。
準備好用戶信息
將會使用到的用戶信息包括:
SecretId:騰訊云賬號內分配
SecretKey:騰訊云賬號內分配
Bucket:存儲桶名稱
Region:區域,即該COS所屬區域
FileUri:請求路徑,如PUT /textfile HTTP1.1,意思是將新上傳的文件放在目標存儲桶根目錄下并命名為textfile
Host:主機,存儲桶具體訪問地址,騰訊云存儲桶詳情可以找到
Content-Length:上傳文件時必須的請求頭
創建參數
先看一個官方文檔給出的栗子
通過 RESTful API 對 COS 發起的 HTTP 簽名請求,使用標準的 HTTP Authorization 頭部來傳遞,如下例所示:
PUT /testfile2 HTTP/1.1
Host: bucket1-1254000000.cos.ap-beijing.myqcloud.com
x-cos-content-sha1: 7b502c3a1f48c8609ae212cdfb639dee39673f5e
x-cos-storage-class: standard
Hello world
解讀一下,這是一個很簡單的http請求,第一行是請求行,第二、三、四行都是請求頭,先放在這兒,后面會用到。按照官方文檔,先準備好必需的參數,參數均已鍵值對方式存在,首先看看官方給出的完整簽名結構
q-sign-algorithm=sha1&q-ak=[SecretID]&q-sign-time=[SignTime]&
q-key-time=[KeyTime]&q-header-list=[SignedHeaderList]&
q-url-param-list=[SignedParameterList]&q-signature=[Signature]
文本中每一個方括號中的內容就是用戶信息,其實sha1也是一個參數截止到發文官方文檔表示只支持sha1因此直接填寫即可,其它的以下逐一解讀
q-xxx:參數中的鍵,固定值,接口設定
[SecretID]:對應客戶的SecretId,如AKIDQjz3ltompVjBni5LitkWHFlFpwkn9U5q
[SignTime]:一個由本簽名起始時間和結束時間組成的字符串,官方文檔解釋的很清楚,不再贅述
[KeyTime]:與[SignTime]相同
[SignedHeaderList]:HTTP請求頭所組成,官方文檔說明需從 key:value 中提取部分或全部 key...,第一次沒有理解怎么還允許部分,到底是全部還是部分。再次研究接口時,明白了,數據來自對接口的原始請求,即還沒計算簽名前的HTTP Request Headers。往回倒兩步來看2. 創建參數開始時給出的請求示例。Host、x-cos-content-sha1、x-cos-storage-class說明該請求全部請求頭有三個,因此[SignedHeaderList]可以有這三個請求頭組成,也可以挑兩個甚至一個(我按照理論猜測未測試)。該值是由請求頭的Key部分組成,Key需轉化為小寫并且以字典排序再用連接符;連接,正確處理后的結果應該是host;x-cos-content-sha1;x-cos-storage-class。當然如果有Content-Type這樣的請求頭,結果應為content-type;host;x-cos-content-sha1;x-cos-storage-class。
[SignedParameterList]:官方文檔說明該值來自接口中的HTTP請求部分,即第一行請求行。官方給出的例子是HTTP請求GET /?prefix=abc&max-keys=20時,[SignedParameterList]為max-keys;prefix或prefix。按字面意思如果是非GET請求應該就沒有查詢部分也就沒有參數,該值應該是空。
[Signature]:使用特定的算法計算出的簽名字符串,后面細說。
編寫
根據上面的結構分解,可以了解到以下結構
請求簽名是由7個鍵值對組成的字符串
請求簽名最后一個值[Signature]需要進一步計算
在創建請求簽名之前,HTTP原始請求頭最好就設計好包括哪些字段,最好只包括最必要的如Host,因為原始請求頭將作為一種數據源影響請求簽名的計算結果
了解了結構之后,開始創建一個簽名,為了和官方文檔比對結果,用戶信息使用官方文檔給出的內容
用戶信息
APPID:1254000000(在計算請求簽名的過程中我沒發現該參數有什么用)
SecretId:AKIDQjz3ltompVjBni5LitkWHFlFpwkn9U5q
SecretKey:BQYIM75p8x0iWVFSIgqEKwFprpRSVHlz
Bucket:bucket1-1254000000
Region:ap-beijing
FileUri:/testfile2
Host:bucket1-1254000000.cos.ap-beijing.myqcloud.com(Host的構造可以從官方給出的示例自行組成或拆分)
Content-Length:示例中未有此項
x-cos-content-sha1: 7b502c3a1f48c8609ae212cdfb639dee39673f5e
x-cos-storage-class: standard
請求簽名結果比照
根據用戶信息,帶入到請求簽名結構中,對應關系如下
鍵(key)
值(value)
備注
q-sign-algorithm
sha1
目前僅支持 sha1 簽名算法
q-ak
AKIDQjz3ltompVjBni5LitkWHFlFpwkn9U5q
SecretId 字段
q-sign-time
1417773892;1417853898
2014/12/5 18:04:52 到 2014/12/6 16:18:18
q-key-time
1417773892;1417853898
2014/12/5 18:04:52 到 2014/12/6 16:18:18
q-header-list
host;x-cos-content-sha1;x-cos-storage-class
HTTP 頭部 key 的字典順序排序列表
q-url-param-list
HTTP 參數列表為空
q-signature
14e6ebd7955b0c6da532151bf97045e2c5a64e10
通過代碼計算所得
以上是官方文檔給出的“結果”,也就是說如果自己計算出來的7個鍵值對跟表格中結果一致,即說明算法正確。
先計算已有的值
/**
* 計算簽名
* secretId、secretKey 為必需參數,qSignStart、qSignEnd為調試需要,測試通過后應取消,改為方法內自動創建
*/
function get_authorization( $secretId, $secretKey, $qSignStart, $qSignEnd, $fileUri, $headers ){
/*
* 計算COS簽名
* 2018-05-17
* author:cinlap
* ref:https://cloud.tencent.com/document/product/436/7778
*/
$qSignTime = "$qSignStart;$qSignEnd"; //unix_timestamp;unix_timestamp
$qKeyTime = $qSignTime;
$header_list = get_q_header_list($headers);
//如果 Uri 中帶有 ?的請求參數,該處應為數組排序后的字符串組合
$url_param_list = '';
//compute signature
$httpMethod = 'put';
$httpUri = $fileUri;
//與 q-url-param-list 相同
$httpParameters = $url_param_list;
//將自定義請求頭分解為 & 連接的字符串
$headerString = get_http_header_string( $headers );
// 計算簽名中的 signature 部分
$signTime = $qSignTime;
$signKey = hash_hmac('sha1', $signTime, $secretKey);
$httpString = "$httpMethod\n$httpUri\n$httpParameters\n$headerString\n";
$sha1edHttpString = sha1($httpString);
$stringToSign = "sha1\n$signTime\n$sha1edHttpString\n";
$signature = hash_hmac('sha1', $stringToSign, $signKey);
//組合結果
$authorization = "q-sign-algorithm=sha1&q-ak=$secretId&q-sign-time=$qSignTime&q-key-time=$qKeyTime&q-header-list=$header_list&q-url-param-list=$url_param_list&q-signature=$signature";
return $authorization;
}
為了測試,該方法參數應該是多過需要了,前六個參數是已經給出的,是來自用戶的,因此直接賦值即可
$authorization = "q-sign-algorithm=sha1&q-ak=$secretId&q-sign-time=$qSignTime&q-key-time=$qKeyTime...
q-header-list
這個值需要計算,邏輯是從HTTP請求頭中,選擇全部或部分,將每項的key轉化為小寫并按字典排序,最終輸出成字符串,多個key用字符 ; 連接。代碼如下
```php
/**
按COS要求對header_list內容進行轉換
提取所有key
字典排序
key轉換為小寫
多對key=value之間用連接符連接
*/
function get_q_header_list($headers){
if(!is_array($headers)){
return false;
}
try{
$tmpArray = array();
foreach( $headers as $key=>$value){
array_push($tmpArray, strtolower($key));
}
sort($tmpArray);
return implode(';', $tmpArray);
}
catch(Exception $error){
return false;
}
}
本例中,HTTP請求頭是三個,因此輸出結果應該是host;x-cos-content-sha1;x-cos-storage-class```,和官方給出結果一致。
q-url-param-list
上面講過,這個值是HTTP請求參數,對于PUT方法沒有?后參數,自然值為0,所以代碼中“偷懶”直接給了空字符串,實際應該根據用戶給的URI做個智能判斷之類的,但是想想從邏輯上不做也行。
最后重點是計算 Signature
算法官方已經給出了,PHP還是很幸福的直接拿來用,先看一下 $httpString 的組成。由四個部分組成 $httpMethod、 $httpUri、 $httpParameters、 $headerString。
$httpMethod:HTTP請求方法,小寫,比如 put、get
$httpUri:HTTP請求的URI部分,從“/”虛擬根開始,如 /testfile 說明在存儲桶根目錄下創建一個叫 testfile 的文件,/image/face1.jpg 說明在根目錄/image目錄下建立一個叫 face1.jpg 的文件,至于是不是圖片文件,不管
$httpParameters:HTTP請求參數,即請求URI中?后面的部分,本例調用的是 PUT Object 接口,因此為空
$headerString:這個地方就需要計算了,邏輯是根據請求頭,選擇全部或部分請求頭,把每項的key都轉換為小寫,把value都進行URLEncode轉換,每項格式都改為key=value,然后按照key進行字典排序,最后把它們用連接符 & 組成字符串。這是我整理的邏輯,代碼如下
```php
/**
按COS要求從數組中獲取 Signature 中 [HttpString] 內容
標準格式 key=value&key=value&...
數組元素按鍵字典排序 *
key轉換為小寫
value進行UrlEncode轉換
轉換為key=value格式
多對key=value之間用連接符連接
*/
function get_http_header_string($headers){
if(!is_array($headers)){
return false;
}
try{
$tmpArray = array();
foreach($headers as $key => $value){
$tmpKey = strtolower($key);
$tmpArray[$tmpKey] = urlencode($value);
}
ksort($tmpArray);
$headerArray = array();
foreach( $tmpArray as $key => $value){
array_push($headerArray, "$key=$value");
}
return implode('&', $headerArray);
}
catch(Exception $error){
return false;
}
}
```
組合輸出
至此,請求簽名中7個值都有了,有的是來自用戶信息,有的需要計算,需要計算的上面也給出了所有的計算方法和為什么如此計算的個人理解。最后只需要按照官方要求進行輸出即可。看一下
分類:
技術點:
php
By ? 2017 likecs 版權所有.
粵ICP備12038626號-2
Powered By WordPress . Theme by Luju