PHP⽣成腾讯云COS请求签名
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,可以在控制台页⾯获取
q-sign-time
当前签名的有效起⽌时间,Unix时间戳格式,英⽂半⾓分号;分割,格式如1480932292;1481012298
q-key-time
与 q-sign-time 值相同
q-header-list
个⼈理解,由HTTP请求头组成,取全部或部分请求头,将key:value形式的请求项的 key 部分取出,转化⼩写,多个 key 按字典排序,以字符;连接,最终组成字符串
如原始请求头有两个:
qcloud
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: qcloud
x-cos-content-sha1: 7b502c3a1f48c8609ae212cdfb639dee39673f5e
x-cos-storage-class: standard
Hello world
计算签名后应该得到的HTTP请求:
PUT /testfile2 HTTP/1.1
Host: qcloud
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 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-time1417773892;14178538982014/12/5 18:04:52 到 2014/12/6 16:18:18
q-key-time1417773892;14178538982014/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-signature14e6ebd7955b0c6da532151bf97045e2c5a64e10通过代码计算所得
但 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:t/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=$
$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 中 ? 后⾯的部分,本例调⽤的是接⼝,因此为空。如果不为空,需要把请求参数每⼀项的 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个值都有了,有的是来⾃⽤户信息,有的需要计算,需要计算的上⾯也给出了所有的计算⽅法和为什么如此计算的个⼈理解。最后只需要按照官⽅要求进⾏输出即可。看⼀下 ,在PostMan中选择Post⽅法,选择form-data⽅式提交数据,在Body中给出所有⽤户参数(这个地⽅为了测试算法是否与官⽅⼀直,所以⼏乎所有的值都是Post提交上去的,实际时间、Host都可以在算法中创建)
提交后,返回结果
字很⼩,单独把结果提取出来
{
"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-lis    "Host": "qcloud",
"Content-Length": "12000"
}
Host和Content-Length是我⾃定义输出,主要是看Authorization部分,和官⽅⽂档给出的结果值完全⼀致,说明算法逻辑正确。
吐槽和反思
version 0.2
昨天基于对腾讯云API的“愤慨”和怕忘记⽽急于记下思路的原因,写的很是潦草,发觉吐槽⼈家官⽅⽂档顺序不同⾃⼰的更不同,今天重写
version 0.1
之前 C# 做过⼀次对接⼝的研究,死活不⾏,最后通过腾讯技术⽀持提供的AWS的SDK调⽤成功,真是⼼累。本次需要⽤PHP做项⽬,必须要攻克,本来不应该多难,必须要为
⾃⼰的智⼒和年龄讨个说法。不过还是想再次吐槽官⽅⽂档,看似详尽,顺序前后不够⼀致,⽰例代码细节⽐如参数不够统⼀,造成新⼿容易误解怎么前后对不上,对⼀些细节
和前后逻辑不能第⼀时间融汇贯通。⽐如我⾃⼰,就是再次研究接⼝时,才理解⾥边关于[SignHeaderList]等和计算[Signature]有什么关联。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。