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

时间:2022-06-18
本文章向大家介绍cos-临时签名生成(附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['Domain'] . '/v2/index.php?' . json2str($opt);
    $formatString = urldecode($formatString);
    $sign = hash_hmac('sha1', $formatString, $key);
    $sign = base64_encode(hex2bin($sign));
    return $sign;
}

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

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

    global $config;

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

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

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

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

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

    $url = $config['Url'] . '?' . json2str($params);
    $ch = curl_init($url);
    $config['Proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['Proxy']);
    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['data'])) $result = $result['data'];

    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 : 'get');
    $pathname = $pathname ? $pathname : '/';
    substr($pathname, 0, 1) != '/' && ($pathname = '/' . $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 < $len; $i++) {
            $key = $keyList[$i];
            $val = isset($obj[$key]) ? $obj[$key] : '';
            $key = strtolower($key);
            $list[] = rawurlencode($key) . '=' . rawurlencode($val);
        }
        return implode('&', $list);
    }

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

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

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

    // 步骤二:构成 FormatString
    $formatString = implode("n", array(strtolower($method), $pathname, obj2str($query), obj2str($headers), ''));

    header('x-test-method', $method);
    header('x-test-pathname', $pathname);

    // 步骤三:计算 StringToSign
    $stringToSign = implode("n", array('sha1', $qSignTime, sha1($formatString), ''));

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

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

    return $authorization;
}

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

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

// 获取临时密钥,计算签名
$tempKeys = getTempKeys();
if ($tempKeys && isset($tempKeys['credentials'])) {
    $data = array(
        'Authorization' => getAuthorization($tempKeys, $method, $pathname),
        'XCosSecurityToken' => $tempKeys['credentials']['sessionToken'],
    );
} else {
    $data = array('error'=> $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"

}