cos-临时签名生成(附php脚本)

上篇文章举例了临时密钥生成,此文章为生成临时签名。

请参考此脚本生成:

代码语言:php
复制
<?php
// 临时密钥计算样例

// 配置参数
$config = array(
'Url' => 'https://sts.api.qcloud.com/v2/index.php',
'Domain' => 'sts.api.qcloud.com',
'Proxy' => '',
'SecretId' => 'API密钥ID', // 固定密钥
'SecretKey' => 'API密钥KEY', // 固定密钥
'Bucket' => '存储桶名称(name-125112233)',
'Region' => 'ap-chengdu', //存储桶地域
'AllowPrefix' => '', // 这里改成允许的路径前缀,这里可以根据自己网站的用户登录态判断允许上传的目录,例子: 或者 a/* 或者 a.jpg
);

// 缓存临时密钥
if (!isset($_SESSION['tempKeysCache'])) {
$_SESSION['tempKeysCache'] = array(
'policyStr' => '',
'expiredTime' => 0
);
}

// obj 转 query string
function json2str($obj) {
ksort($obj);
$arr = array();
foreach (obj as key => $val) {
array_push(arr, key . '=' . $val);
}
return join('&', $arr);
}

// 计算临时密钥用的签名
function getSignature(opt, key, $method) {
global $config;
formatString = method . config[&#39;Domain&#39;] . &#39;/v2/index.php?&#39; . json2str(opt);
formatString = urldecode(formatString);
sign = hash_hmac(&#39;sha1&#39;, formatString, $key);
sign = base64_encode(hex2bin(sign));
return $sign;
}

// 计算临时密钥用的签名
function resourceUrlEncode($str) {
str = rawurlencode(str);
//特殊处理字符 !()~
str = str_replace(&#39;%2F&#39;, &#39;/&#39;, str);
str = str_replace(&#39;%2A&#39;, &#39;*&#39;, str);
str = str_replace(&#39;%21&#39;, &#39;!&#39;, str);
str = str_replace(&#39;%28&#39;, &#39;(&#39;, str);
str = str_replace(&#39;%29&#39;, &#39;)&#39;, str);
str = str_replace(&#39;%7E&#39;, &#39;~&#39;, str);
return $str;
}

// 获取临时密钥
function getTempKeys() {

global $config;

// 判断是否修改了 AllowPrefix
if ($config[&#39;AllowPrefix&#39;] === &#39;_ALLOW_DIR_/*&#39;) {
    return array(&#39;error&#39;=&gt; &#39;请修改 AllowPrefix 配置项,指定允许上传的路径前缀&#39;);
}

$ShortBucketName = substr($config[&#39;Bucket&#39;],0, strripos($config[&#39;Bucket&#39;], &#39;-&#39;));
$AppId = substr($config[&#39;Bucket&#39;], 1 + strripos($config[&#39;Bucket&#39;], &#39;-&#39;));
$policy = array(
    &#39;version&#39;=&gt; &#39;2.0&#39;,
    &#39;statement&#39;=&gt; array(
        array(
            &#39;action&#39;=&gt; array(
                // // 这里可以从临时密钥的权限上控制前端允许的操作
                // &#39;name/cos:*&#39;, // 这样写可以包含下面所有权限

                // // 列出所有允许的操作
                // // ACL 读写
                // &#39;name/cos:GetBucketACL&#39;,
                // &#39;name/cos:PutBucketACL&#39;,
                // &#39;name/cos:GetObjectACL&#39;,
                // &#39;name/cos:PutObjectACL&#39;,
                // // 简单 Bucket 操作
                // &#39;name/cos:PutBucket&#39;,
                // &#39;name/cos:HeadBucket&#39;,
                // &#39;name/cos:GetBucket&#39;,
                // &#39;name/cos:DeleteBucket&#39;,
                // &#39;name/cos:GetBucketLocation&#39;,
                // // Versioning
                // &#39;name/cos:PutBucketVersioning&#39;,
                // &#39;name/cos:GetBucketVersioning&#39;,
                // // CORS
                // &#39;name/cos:PutBucketCORS&#39;,
                // &#39;name/cos:GetBucketCORS&#39;,
                // &#39;name/cos:DeleteBucketCORS&#39;,
                // // Lifecycle
                // &#39;name/cos:PutBucketLifecycle&#39;,
                // &#39;name/cos:GetBucketLifecycle&#39;,
                // &#39;name/cos:DeleteBucketLifecycle&#39;,
                // // Replication
                // &#39;name/cos:PutBucketReplication&#39;,
                // &#39;name/cos:GetBucketReplication&#39;,
                // &#39;name/cos:DeleteBucketReplication&#39;,
                // // 删除文件
                // &#39;name/cos:DeleteMultipleObject&#39;,
                // &#39;name/cos:DeleteObject&#39;,
                // 简单文件操作
                &#39;name/cos:PutObject&#39;,
                &#39;name/cos:PostObject&#39;,
                &#39;name/cos:AppendObject&#39;,
                &#39;name/cos:GetObject&#39;,
                &#39;name/cos:HeadObject&#39;,
                &#39;name/cos:OptionsObject&#39;,
                &#39;name/cos:PutObjectCopy&#39;,
                &#39;name/cos:PostObjectRestore&#39;,
                // 分片上传操作
                &#39;name/cos:InitiateMultipartUpload&#39;,
                &#39;name/cos:ListMultipartUploads&#39;,
                &#39;name/cos:ListParts&#39;,
                &#39;name/cos:UploadPart&#39;,
                &#39;name/cos:CompleteMultipartUpload&#39;,
                &#39;name/cos:AbortMultipartUpload&#39;,
            ),
            &#39;effect&#39;=&gt; &#39;allow&#39;,
            &#39;principal&#39;=&gt; array(&#39;qcs&#39;=&gt; array(&#39;*&#39;)),
            &#39;resource&#39;=&gt; array(
                &#39;qcs::cos:&#39; . $config[&#39;Region&#39;] . &#39;:uid/&#39; . $AppId . &#39;:prefix//&#39; . $AppId . &#39;/&#39; . $ShortBucketName . &#39;/&#39;,
                &#39;qcs::cos:&#39; . $config[&#39;Region&#39;] . &#39;:uid/&#39; . $AppId . &#39;:prefix//&#39; . $AppId . &#39;/&#39; . $ShortBucketName . &#39;/&#39; . resourceUrlEncode($config[&#39;AllowPrefix&#39;])
            )
        )
    )
);

$policyStr = str_replace(&#39;\\/&#39;, &#39;/&#39;, json_encode($policy));
$Action = &#39;GetFederationToken&#39;;
$Nonce = rand(10000, 20000);
$Timestamp = time() - 1;
$Method = &#39;GET&#39;;

$params = array(
    &#39;Action&#39;=&gt; $Action,
    &#39;Nonce&#39;=&gt; $Nonce,
    &#39;Region&#39;=&gt; &#39;&#39;,
    &#39;SecretId&#39;=&gt; $config[&#39;SecretId&#39;],
    &#39;Timestamp&#39;=&gt; $Timestamp,
    &#39;durationSeconds&#39;=&gt; 7200,
    &#39;name&#39;=&gt; &#39;cos&#39;,
    &#39;policy&#39;=&gt; urlencode($policyStr)
);
$params[&#39;Signature&#39;] = urlencode(getSignature($params, $config[&#39;SecretKey&#39;], $Method));

$url = $config[&#39;Url&#39;] . &#39;?&#39; . json2str($params);
$ch = curl_init($url);
$config[&#39;Proxy&#39;] &amp;&amp; curl_setopt($ch, CURLOPT_PROXY, $config[&#39;Proxy&#39;]);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
if(curl_errno($ch)) $result = curl_error($ch);
curl_close($ch);

$result = json_decode($result, 1);
if (isset($result[&#39;data&#39;])) $result = $result[&#39;data&#39;];

return $result;

}

// 计算 COS API 请求用的签名
function getAuthorization(keys, method, $pathname)
{
// 获取个人 API 密钥 https://console.qcloud.com/capi
SecretId = keys['credentials']['tmpSecretId'];
SecretKey = keys['credentials']['tmpSecretKey'];

// 整理参数
$query = array();
$headers = array();
$method = strtolower($method ? $method : &#39;get&#39;);
$pathname = $pathname ? $pathname : &#39;/&#39;;
substr($pathname, 0, 1) != &#39;/&#39; &amp;&amp; ($pathname = &#39;/&#39; . $pathname);

// 工具方法
function getObjectKeys($obj)
{
    $list = array_keys($obj);
    sort($list);
    return $list;
}

function obj2str($obj)
{
    $list = array();
    $keyList = getObjectKeys($obj);
    $len = count($keyList);
    for ($i = 0; $i &lt; $len; $i++) {
        $key = $keyList[$i];
        $val = isset($obj[$key]) ? $obj[$key] : &#39;&#39;;
        $key = strtolower($key);
        $list[] = rawurlencode($key) . &#39;=&#39; . rawurlencode($val);
    }
    return implode(&#39;&amp;&#39;, $list);
}

// 签名有效起止时间
$now = time() - 1;
$expired = $now + 600; // 签名过期时刻,600 秒后

// 要用到的 Authorization 参数列表
$qSignAlgorithm = &#39;sha1&#39;;
$qAk = $SecretId;
$qSignTime = $now . &#39;;&#39; . $expired;
$qKeyTime = $now . &#39;;&#39; . $expired;
$qHeaderList = strtolower(implode(&#39;;&#39;, getObjectKeys($headers)));
$qUrlParamList = strtolower(implode(&#39;;&#39;, getObjectKeys($query)));

// 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
// 步骤一:计算 SignKey
$signKey = hash_hmac(&#34;sha1&#34;, $qKeyTime, $SecretKey);

// 步骤二:构成 FormatString
$formatString = implode(&#34;\n&#34;, array(strtolower($method), $pathname, obj2str($query), obj2str($headers), &#39;&#39;));

header(&#39;x-test-method&#39;, $method);
header(&#39;x-test-pathname&#39;, $pathname);

// 步骤三:计算 StringToSign
$stringToSign = implode(&#34;\n&#34;, array(&#39;sha1&#39;, $qSignTime, sha1($formatString), &#39;&#39;));

// 步骤四:计算 Signature
$qSignature = hash_hmac(&#39;sha1&#39;, $stringToSign, $signKey);

// 步骤五:构造 Authorization
$authorization = implode(&#39;&amp;&#39;, array(
    &#39;q-sign-algorithm=&#39; . $qSignAlgorithm,
    &#39;q-ak=&#39; . $qAk,
    &#39;q-sign-time=&#39; . $qSignTime,
    &#39;q-key-time=&#39; . $qKeyTime,
    &#39;q-header-list=&#39; . $qHeaderList,
    &#39;q-url-param-list=&#39; . $qUrlParamList,
    &#39;q-signature=&#39; . $qSignature
));

return $authorization;

}

// 开启 session 缓存临时密钥
session_start();

// 获取前端过来的参数
method = isset(_GET['method']) ? $_GET['method'] : 'get';
pathname = isset(_GET['pathname']) ? $_GET['pathname'] : '/';

// 获取临时密钥,计算签名
$tempKeys = getTempKeys();
if (tempKeys &amp;&amp; isset(tempKeys['credentials'])) {
$data = array(
'Authorization' => getAuthorization(tempKeys, method, $pathname),
'XCosSecurityToken' => $tempKeys['credentials']['sessionToken'],
);
} else {
data = array(&#39;error&#39;=&gt; tempKeys);
}

// 返回数据给前端
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); // 这里修改允许跨域访问的网站
header('Access-Control-Allow-Headers: origin,accept,content-type');
echo json_encode($data);

生成格式:

{

"Authorization": "q-sign-algorithm=sha1&q-ak=AKID10FMMEmIr2rxFeNfqQtV10HpH416cyip&q-sign-time=1551940851;1551941451&q-key-time=1551940851;1551941451&q-header-list=&q-url-param-list=&q-signature=3d1ffe8e79d2aa4309e59499190a7757a8fbf648",

"XCosSecurityToken": "a8873989ef84cb38f0d9ba44c959d546ad58d0f430001"

}