PHP生成騰訊雲COS請求簽名

来源:https://www.cnblogs.com/cinlap/archive/2018/05/17/9052705.html
-Advertisement-
Play Games

目標 使用 PHP 創建 COS 介面所需要的請求簽名,按照官方示例,請求簽名應用在需要身份校驗的場景,即非公有讀許可權時。否則在請求API介面時,就必須攜帶簽名作為請求頭的一部分傳遞。 步驟 準備好用戶信息 1. 將會使用到的用戶信息包括: SecretId:騰訊雲賬號內分配 SecretKey:騰 ...


COS和請求簽名是什麼

COS 是騰訊雲對象存儲的縮寫及簡稱,請求簽名是第三方在調用COS相關介面時需要按需提供的、經過特定演算法創建而成的一組字元串信息,將唯一的標識當前第三方身份,提供通信雙方的身份識別,只有有效的簽名COS才會提供服務

目標

使用 PHP 創建 COS 介面所需要的請求簽名,與官方文檔給出的示例做比較,驗證演算法的正確性

認識請求簽名

先來看一條官方文檔給出的請求簽名的樣子

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]

請求簽名特點總結

  • 是一串字元串
  • key=value的鍵值對格式,key為固定值
  • 一共有7對key=value
  • sha1也是參數,但截止到官方發文只支持sha1,因此可以直接賦值
  • SignedHeaderList、SignedParameterList、Signature三個value需要通過演算法生成

鍵值對的具體描述參見官方文檔

逐個擊破

請求簽名一共需要7個值,下麵一一講解,各個擊破

q-sign-algorithm

簽名演算法,官方目前僅支持 sha1,因此直接給值即可

q-ak

賬戶ID,即用戶的 SecretId,可以在控制台 雲API密鑰 頁面獲取

q-sign-time

當前簽名的有效起止時間,Unix時間戳格式,英文半形分號 ; 分割,格式如 1480932292;1481012298

q-key-time

與 q-sign-time 值相同

q-header-list

個人理解,由HTTP請求頭組成,取全部或部分請求頭,將 key:value 形式的請求項的 key 部分取出,轉化小寫,多個 key 按字典排序,以字元 ; 連接,最終組成字元串

如原始請求頭有兩個:

Host:bucket1-1254000000.cos.ap-beijing.myqcloud.com
Content-Type:image/jpeg

key 就是 Host 和 Content-Type,經過運算後輸出 content-type;host

q-url-param-list

個人理解,由HTTP請求參數組成,取全部或部分請求參數,將 key=value 形式的請求參數的 key 部分取出,轉化小寫,多個 key 按字典排序,以字元 ; 連接,最終組成字元串

如原始HTTP請求為:

GET /?prefix=abc&max-keys=20

key 就是 prefix 和 max-keys,經過運算後輸出 max-keys;prefix,如果請求沒有參數比如 put、post,此處即為空

q-signature

根據HTTP內容計算簽名,演算法由COS提供,只需按要求給值

官方示例及參照結果

在開始編寫邏輯之前,先看一下官方示例給出的參考值,以及經過計算後的結果,以便和自己開發的邏輯進行結果比對

HTTP原始請求,也可以理解為計算簽名前或不需要簽名時的HTTP請求:

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請求:

PUT /testfile2 HTTP/1.1
Host: bucket1-1254000000.cos.ap-beijing.myqcloud.com
x-cos-content-sha1: 7b502c3a1f48c8609ae212cdfb639dee39673f5e
x-cos-storage-class: standard
Authorization: q-sign-algorithm=sha1&q-ak=AKIDQjz3ltompVjBni5LitkWHFlFpwkn9U5q&> q-sign-time=1417773892;1417853898&q-key-time=1417773892;1417853898&q-header-list=host;x-cos-content-sha1;x-cos-storage-class&q-url-param-list=&q-signature=14e6ebd7955b0c6da532151bf97045e2c5a64e10

Hello world

結論:演算法如果能得到 Authorization 後的那一串字元串即為正確

準備工作

來看一下(官方提供的)用戶信息以及HTTP信息:

  • SecretId:AKIDQjz3ltompVjBni5LitkWHFlFpwkn9U5q
  • SecretKey:BQYIM75p8x0iWVFSIgqEKwFprpRSVHlz
  • 簽名有效起始時間:1417773892
  • 簽名有效停止時間:1417853898
  • HTTP原始請求頭:根據上一節示例不難得到HTTP原始請求有三項內容 Host、x-cos-content-sha1 和 x-cos-storage-class
  • HTTP請求參數:是 PUT 請求,沒有 ? 參數

計算簽名

將準備工作中的各項參數帶入請求簽名規則,不難就可以得到結果,如下表:

鍵(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 通過代碼計算所得

但 q-signature 怎麼來的?

剛纔說到,q-signature 也需要特定演算法計算得來,下麵就說明如何計算

計算請求簽名

先看代碼:

/**
 * 計算簽名
 * secretId、secretKey 為必需參數,qSignStart、qSignEnd為調試需要,測試通過後應取消,改為方法內自動創建
 */
function get_authorization( $secretId, $secretKey, $qSignStart, $qSignEnd, $fileUri, $headers ){
    /* 
    * 計算COS簽名
    * 2018-05-17
    * author:cinlap <cash216@163>
    * 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...

$header_list 這個值要符合 q-header-list 規則因此需要計算,邏輯是上文已經描述,是從既定的請求項中抽出 key 組成有序字元串,代碼如下:

/**
 * 按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;
    }
}

$url-param-list 上面講過,這個值是HTTP請求參數,對於 PUT 方法沒有 ? 參數,自然值為空,所以代碼中“偷懶”直接給了空字元串。

Signature 的計算和需要小心的地方

官方已經給出了完整的演算法,PHP 甚至還有寫好的代碼,應該是很幸福了(但!由於看官方文檔看的頭暈還是踩了坑,隨後一起說明),先看一下 signature 的“格式”:

SignKey = HMAC-SHA1(SecretKey,"[q-key-time]")
HttpString = [HttpMethod]\n[HttpURI]\n[HttpParameters]\n[HttpHeaders]\n
StringToSign = [q-sign-algorithm]\n[q-sign-time]\nSHA1-HASH(HttpString)\n
Signature = HMAC-SHA1(SignKey,StringToSign)

再看一下 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);
  • $signTime:很簡單,起止時間組成的字元串,從上文拿來直接用
  • $signKey:HMAC-SHA1 演算法直接計算即可
  • $httpString:四個部分組成需要分開說
    • $httpMethod:HTTP請求方法,小寫,比如 put、get
    • $httpUri:HTTP請求的URI部分,從“/”虛擬根開始,如 /testfile 說明在存儲桶根目錄下創建一個叫 testfile 的文件,/image/face1.jpg 說明在根目錄/image目錄下建立一個叫 face1.jpg 的文件,至於是不是圖片文件,不管
    • $httpParameters:這是第一個需要小心的地方。由HTTP原始請求參數組成,即請求 URI 中 ? 後面的部分,本例調用的是 PUT Object 介面,因此為空。如果不為空,需要把請求參數每一項的 key 和 value 均轉換小寫,多對 key=value 按字典排序並以 & 相連接
    • $headerString:這是第二個需要小心的地方,由 HTTP 原始請求頭組成,根據請求頭,選擇全部或部分請求頭,把每項的key都轉換為小寫,把value都進行URLEncode轉換,每項格式都改為key=value,然後按照key進行字典排序,最後把它們用連接符 & 組成字元串。這是我整理的邏輯,代碼如下:
/**
 * 按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;
    }
}

為什麼要小心?

HTTP原始請求頭和請求參數用在了四個地方,分別是請求簽名里的 q-header-list 和 Signature 里的 HttpHeaders——兩者都用到了HTTP原始請求頭;請求簽名里的 q-url-param-list 和 Signature 里的 HttpParameters——兩者都用到了HTTP請求參數。一定要保證HTTP請求頭和請求參數所選用的數量和對象一致

  • 相同:生成 q-header-list 的HTTP請求頭數量和成員要和生成 HttpHeaders 的相同,生成 q-url-param-list 的HTTP請求參數數量和成員要和生成 HttpParameters 的相同
  • 不同:q-header-list 和 q-url-param-list 只取 key 部分,HttpHeaders 和 HttpParameters 取 key 和 value 部分

輸出結果和校驗

至此,請求簽名中7個值都有了,有的是來自用戶信息,有的需要計算,需要計算的上面也給出了所有的計算方法和為什麼如此計算的個人理解。最後只需要按照官方要求進行輸出即可。看一下

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • lavaan簡明教程 [中文翻譯版] 譯者註:此文檔原作者為比利時Ghent大學的Yves Rosseel博士,lavaan亦為其開發,完全開源、免費。我在學習的時候順手翻譯了一下,向Yves的開源精神致敬。此翻譯因偷懶部分刪減,但也有增加,有錯誤請留言 「轉載請註明出處」 目錄 lavaan簡明教 ...
  • 恢復內容開始 作者 : liuyang0 來源 : 博客園 常見排序演算法總結與實現 本文使用Java實現這幾種排序。以下是對排序演算法總體的介紹。 冒泡排序 時間複雜度:O(n^2),最優時間複雜度:O(n),平均時間複雜度:O(n^2) 插入排序 時間複雜度:O(n^2),最優時間複雜度:O(n), ...
  • 一、初始Redis 1、Redis特性與優點 速度快。redis所有數據都存放於記憶體;是用C語言實現,更加貼近硬體;使用了單線程架構,避免了多線程競爭問題 基於鍵值對的數據結構,支持的數據結構豐富。它主要提供了5種數據結構: 字元串、 哈希、 列表、 集合、 有序集合, 同時在字元串的基礎之上演變出 ...
  • 一:java不同進位數據的表現形式 二進位表示形式前面加0b(b可以大寫也可以小寫) 八進位表示形式前面加0 十六進位表示形式前面加0x 任意進位到十進位的轉換圖解 十進位到十進位的轉換 12345 = 10000 + 2000 +300 + 40 + 5 =1 *10^4 + 2 *10^3 + ...
  • 使用DOM解析xml文件 要解析的xml文件如下: 解析xml的代碼如下: 基本步驟差不多就是: 首先是先獲得根元素 然後getElementByTagName()獲得相應標簽的node集合 通過集合,如list中的item()獲得集合中的具體元素 最後根據getTextContent()獲得具體元 ...
  • 穿越:從0開始,構建前後端分離應用 攔截器的作用 攔截器是web項目不可或缺的組成部分,一般使用攔截器實現以下功能 1、登錄session驗證 防止瀏覽器端繞過登錄,直接進入到應用 或者session超時後,返回到登錄頁面 2、記錄系統日誌 一個完善的應用系統,應該具備監控功能,通過完善的系統日誌記 ...
  • #include<bits/stdc++.h>using namespace std;main(){double a=2.9939; cout<<fixed<<setprecision(2)<<a;printf("%.3f", a);return 0;} ...
  • JavaSE基礎點一 Java概述 什麼是Java? Java是一門程式設計語言,在說Java語言前先談一下什麼是電腦語言。電腦語言是人與電腦之間通信的語言,它主要由一些指令組成,這些指令包括數字、符號和語法等內容,人可以通過這些指令來指揮電腦進行各種工作。 電腦語言的分類有很多,大體分為 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...