Skip to content

Commit

Permalink
优化签名提示和 sts 例子
Browse files Browse the repository at this point in the history
  • Loading branch information
carsonxu committed Sep 28, 2018
1 parent e9fd341 commit 7665f7f
Show file tree
Hide file tree
Showing 14 changed files with 427 additions and 297 deletions.
79 changes: 79 additions & 0 deletions csp/AllowAction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# 允许操作的判断例子

以下按照 JavaScript 为例子,列举签名允许操作的判断规则

```js
var exist = function (obj, key) {
return obj[key] === undefined;
};
```

## 分片上传

```js
// multipartList 获取已有上传任务
if (pathname === '/' && method === 'get' && exist(query['uploads'])) allow = true;
// multipartListPart 获取单个上传任务的分片列表
if (pathname !== '/' && method === 'get' && exist(query['uploadId'])) allow = true;
// multipartInit 初始化分片上传
if (pathname !== '/' && method === 'post' && exist(query['uploads'])) allow = true;
// multipartUpload 上传文件的单个分片
if (pathname !== '/' && method === 'put' && exist(query['uploadId']) && exist(query['partNumber'])) allow = true;
// multipartComplete 完成一次分片上传
if (pathname !== '/' && method === 'post' && exist(query['uploadId'])) allow = true;
```

## 简单上传

```js
// putObject 简单上传文件
if (pathname !== '/' && method === 'put' && !exist(query['acl'])) allow = true;
// postObject 允许表单上传文件
if (pathname === '/' && method === 'post' && !exist(query['delete'])) allow = true;
```

## 获取和修改权限策略

```js
// getBucketAcl 获取 Bucket 权限
if (pathname === '/' && method === 'get' && !exist(query['acl'])) allow = true;
// putBucketAcl 修改 Bucket 权限
if (pathname === '/' && method === 'put' && !exist(query['acl'])) allow = true;
// getBucketPolicy 获取权限策略
if (pathname === '/' && method === 'get' && !exist(query['policy'])) allow = true;
// putBucketPolicy 修改权限策略
if (pathname === '/' && method === 'put' && !exist(query['policy'])) allow = true;
// getObjectAcl 获取 Object 权限
if (pathname !== '/' && method === 'get' && !exist(query['acl'])) allow = true;
// putObjectAcl 修改 Object 权限
if (pathname !== '/' && method === 'put' && !exist(query['acl'])) allow = true;
```

## 获取和修改生命周期

```js
// getBucketLifecycle 获取 Bucket Lifecycle
if (pathname === '/' && method === 'get' && !exist(query['lifecycle'])) allow = true;
// putBucketLifecycle 修改 Bucket Lifecycle
if (pathname === '/' && method === 'put' && !exist(query['lifecycle'])) allow = true;
```

## 获取和修改 Tagging

```js
// getBucketTagging 获取 Bucket Tagging
if (pathname === '/' && method === 'get' && !exist(query['tagging'])) allow = true;
// putBucketTagging 修改 Bucket Tagging
if (pathname === '/' && method === 'put' && !exist(query['tagging'])) allow = true;
// deleteBucketTagging 删除 Bucket Tagging
if (pathname === '/' && method === 'delete' && !exist(query['tagging'])) allow = true;
```

## 删除文件

```js
// deleteMultipleObject 批量删除文件
if (pathname === '/' && method === 'post' && !exist(query['delete'])) allow = true;
// deleteObject 删除单个文件
if (pathname !== '/' && method === 'delete') allow = true;
```
146 changes: 146 additions & 0 deletions csp/auth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

/**
* php 签名样例
*/

function isActionAllow($method, $pathname, $query, $headers)
{

$allow = true;

// // TODO 这里判断自己网站的登录态
// if ($!logined) {
// $allow = false;
// return $allow;
// }

// 请求可能带有点所有 action
// acl,cors,policy,location,tagging,lifecycle,versioning,replication,versions,delete,restore,uploads

// 请求跟路径,只允许获取 UploadId
if ($pathname === '/' && !($method === 'get' && isset($query['uploads']))) {
$allow = false;
}

// 不允许前端获取和修改文件权限
if ($pathname !== '/' && isset($query['acl'])) {
$allow = false;
}

// 这里应该根据需要,限制当前站点的用户只允许操作什么样的路径
if ($method === 'delete' && $pathname !== '/') { // 这里控制是否允许删除文件
// TODO 这里控制是否允许删除文件
}
if ($method === 'put' && $pathname !== '/') { // 这里控制是否允许上传和修改文件
// TODO 这里控制是否允许上传和修改文件
}
if ($method === 'get' && $pathname !== '/') { // 这里控制是否获取文件和文件相关信息
// TODO 这里控制是否允许获取文件和文件相关信息
}

return $allow;

}

/*
* 获取签名
* @param string $method 请求类型 method
* @param string $pathname 文件名称
* @param array $query query参数
* @param array $headers headers
* @return string 签名字符串
*/
function getAuthorization($method, $pathname, $query, $headers)
{

// 获取个人 API 密钥 https://console.qcloud.com/capi
$SecretId = 'AKIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$SecretKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

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

// 注意这里要过滤好允许什么样的操作
if (!isActionAllow($method, $pathname, $query, $headers)) {
return 'action deny';
}

// 工具方法
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), ''));

// 步骤三:计算 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;
}


// 获取前端过来的参数
$params = json_decode(file_get_contents("php://input"), 1);
$pathname = isset($params['pathname']) ? $params['pathname'] : '/';
$method = isset($params['method']) ? $params['method'] : 'get';
$query = isset($params['query']) ? $params['query'] : array();
$headers = isset($params['headers']) ? $params['headers'] : array();

// 返回数据给前端
header('Content-Type: text/plain');
header('Allow-Control-Allow-Origin: http://127.0.0.1'); // 这里修改允许跨域访问的网站
header('Allow-Control-Allow-Headers: origin,accept,content-type');
echo getAuthorization($method, $pathname, $query, $headers);
38 changes: 13 additions & 25 deletions csp/sts.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,24 @@
);

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

// 计算临时密钥用的签名
function getSignature($opt, $key, $method) {
global $config;
$formatString = $method . $config['Domain'] . '/v2/index.php?' . json2str($opt);
$formatString = urldecode($formatString);
$formatString = $method . $config['Domain'] . '/v2/index.php?' . json2str($opt, 1);
$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() {

Expand Down Expand Up @@ -117,7 +103,7 @@ function getTempKeys() {
'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'])
'qcs::cos:' . $config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/' . $config['AllowPrefix']
)
)
)
Expand All @@ -127,27 +113,29 @@ function getTempKeys() {
$Action = 'GetFederationToken';
$Nonce = rand(10000, 20000);
$Timestamp = time() - 1;
$Method = 'GET';
$Method = 'POST';

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

$url = $config['Url'] . '?' . json2str($params);
$url = $config['Url'];
$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);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json2str($params));
$result = curl_exec($ch);
if(curl_errno($ch)) $result = curl_error($ch);
curl_close($ch);
Expand All @@ -156,7 +144,7 @@ function getTempKeys() {
if (isset($result['data'])) $result = $result['data'];

return $result;
};
}

// 获取临时密钥,计算签名
$tempKeys = getTempKeys();
Expand Down
2 changes: 1 addition & 1 deletion demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ var cos = new COS({
// xhr.send(JSON.stringify(data));


// // 方法三、后端使用固定密钥计算签名,返回给前端
// // 方法三、后端使用固定密钥计算签名,返回给前端,auth.php,注意:后端需要通过 method、pathname 控制好权限,比如不允许 put / 等,这里暂不提供
// var method = (options.Method || 'get').toLowerCase();
// var key = options.Key || '';
// var query = options.Query || {};
Expand Down
Loading

0 comments on commit 7665f7f

Please sign in to comment.