Sts.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <?php
  2. /**
  3. * +----------------------------------------------------------------------
  4. * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  5. * +----------------------------------------------------------------------
  6. * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  7. * +----------------------------------------------------------------------
  8. * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  9. * +----------------------------------------------------------------------
  10. * | Author: CRMEB Team <admin@crmeb.com>
  11. * +----------------------------------------------------------------------
  12. */
  13. namespace crmeb\services\upload\extend\cos;
  14. class Sts
  15. {
  16. // 临时密钥计算样例
  17. function _hex2bin($data)
  18. {
  19. $len = strlen($data);
  20. return pack("H" . $len, $data);
  21. }
  22. // obj 转 query string
  23. function json2str($obj, $notEncode = false)
  24. {
  25. ksort($obj);
  26. $arr = array();
  27. if (!is_array($obj)) {
  28. throw new \Exception('$obj must be an array, the actual value is:' . json_encode($obj));
  29. }
  30. foreach ($obj as $key => $val) {
  31. array_push($arr, $key . '=' . ($notEncode ? $val : rawurlencode($val)));
  32. }
  33. return join('&', $arr);
  34. }
  35. // 计算临时密钥用的签名
  36. function getSignature($opt, $key, $method, $config)
  37. {
  38. $host = "sts.tencentcloudapi.com";
  39. if (array_key_exists('domain', $config)) {
  40. $host = $config['domain'];
  41. }
  42. if (array_key_exists('endpoint', $config)) {
  43. $host = "sts." . $config['endpoint'];
  44. }
  45. $formatString = $method . $host . '/?' . $this->json2str($opt, 1);
  46. $sign = hash_hmac('sha1', $formatString, $key);
  47. $sign = base64_encode($this->_hex2bin($sign));
  48. return $sign;
  49. }
  50. // v2接口的key首字母小写,v3改成大写,此处做了向下兼容
  51. function backwardCompat($result)
  52. {
  53. if (!is_array($result)) {
  54. throw new \Exception('$result must be an array, the actual value is:' . json_encode($result));
  55. }
  56. $compat = array();
  57. foreach ($result as $key => $value) {
  58. if (is_array($value)) {
  59. $compat[lcfirst($key)] = $this->backwardCompat($value);
  60. } elseif ($key == 'Token') {
  61. $compat['sessionToken'] = $value;
  62. } else {
  63. $compat[lcfirst($key)] = $value;
  64. }
  65. }
  66. return $compat;
  67. }
  68. // 获取临时密钥
  69. function getTempKeys($config)
  70. {
  71. $result = null;
  72. try {
  73. if (array_key_exists('policy', $config)) {
  74. $policy = $config['policy'];
  75. } else {
  76. if (array_key_exists('bucket', $config)) {
  77. $ShortBucketName = substr($config['bucket'], 0, strripos($config['bucket'], '-'));
  78. $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-'));
  79. } else {
  80. throw new \Exception("bucket== null");
  81. }
  82. if (array_key_exists('allowPrefix', $config)) {
  83. if (!(strpos($config['allowPrefix'], '/') === 0)) {
  84. $config['allowPrefix'] = '/' . $config['allowPrefix'];
  85. }
  86. } else {
  87. throw new \Exception("allowPrefix == null");
  88. }
  89. if (!array_key_exists('region', $config)) {
  90. throw new \Exception("region == null");
  91. }
  92. $policy = array(
  93. 'version' => '2.0',
  94. 'statement' => array(
  95. array(
  96. 'action' => $config['allowActions'],
  97. 'effect' => 'allow',
  98. 'resource' => array(
  99. 'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':' . $config['bucket'] . $config['allowPrefix']
  100. )
  101. )
  102. )
  103. );
  104. }
  105. $policyStr = str_replace('\\/', '/', json_encode($policy));
  106. $Action = 'GetFederationToken';
  107. $Nonce = rand(10000, 20000);
  108. $Timestamp = time();
  109. $Method = 'POST';
  110. if (array_key_exists('durationSeconds', $config)) {
  111. if (!(is_integer($config['durationSeconds']))) {
  112. throw new \Exception("durationSeconds must be a int type");
  113. }
  114. }
  115. $params = array(
  116. 'SecretId' => $config['secretId'],
  117. 'Timestamp' => $Timestamp,
  118. 'Nonce' => $Nonce,
  119. 'Action' => $Action,
  120. 'DurationSeconds' => $config['durationSeconds'],
  121. 'Version' => '2018-08-13',
  122. 'Name' => 'cos',
  123. 'Region' => $config['region'],
  124. 'Policy' => urlencode($policyStr)
  125. );
  126. $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config);
  127. $url = 'https://sts.tencentcloudapi.com/';
  128. if (array_key_exists('url', $config)) {
  129. $url = $config['url'];
  130. }
  131. if (!array_key_exists('url', $config) && array_key_exists('domain', $config)) {
  132. $url = 'https://sts.' . $config['domain'];
  133. }
  134. if (array_key_exists('endpoint', $config)) {
  135. $url = 'https://sts.' . $config['endpoint'];
  136. }
  137. $ch = curl_init($url);
  138. if (array_key_exists('proxy', $config)) {
  139. $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']);
  140. }
  141. curl_setopt($ch, CURLOPT_HEADER, 0);
  142. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  143. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
  144. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  145. curl_setopt($ch, CURLOPT_POST, 1);
  146. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params));
  147. $result = curl_exec($ch);
  148. if (curl_errno($ch)) $result = curl_error($ch);
  149. curl_close($ch);
  150. $result = json_decode($result, 1);
  151. if (isset($result['Response'])) {
  152. $result = $result['Response'];
  153. if (isset($result['Error'])) {
  154. throw new \Exception("get cam failed");
  155. }
  156. $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds'];
  157. }
  158. $result = $this->backwardCompat($result);
  159. return $result;
  160. } catch (\Exception $e) {
  161. if ($result == null) {
  162. $result = "error: " . $e->getMessage();
  163. } else {
  164. $result = json_encode($result);
  165. }
  166. throw new \Exception($result);
  167. }
  168. }
  169. //申请角色授权
  170. function getRoleCredential($config)
  171. {
  172. $result = null;
  173. try {
  174. if (array_key_exists('policy', $config)) {
  175. $policy = $config['policy'];
  176. } else {
  177. if (array_key_exists('bucket', $config)) {
  178. $ShortBucketName = substr($config['bucket'], 0, strripos($config['bucket'], '-'));
  179. $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-'));
  180. } else {
  181. throw new \Exception("bucket== null");
  182. }
  183. if (array_key_exists('allowPrefix', $config)) {
  184. if (!(strpos($config['allowPrefix'], '/') === 0)) {
  185. $config['allowPrefix'] = '/' . $config['allowPrefix'];
  186. }
  187. } else {
  188. throw new \Exception("allowPrefix == null");
  189. }
  190. if (!array_key_exists('region', $config)) {
  191. throw new \Exception("region == null");
  192. }
  193. $policy = array(
  194. 'version' => '2.0',
  195. 'statement' => array(
  196. array(
  197. 'action' => $config['allowActions'],
  198. 'effect' => 'allow',
  199. 'resource' => array(
  200. 'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':' . $config['bucket'] . $config['allowPrefix']
  201. )
  202. )
  203. )
  204. );
  205. }
  206. if (array_key_exists('roleArn', $config)) {
  207. $RoleArn = $config['roleArn'];
  208. } else {
  209. throw new \Exception("roleArn == null");
  210. }
  211. $policyStr = str_replace('\\/', '/', json_encode($policy));
  212. $Action = 'AssumeRole';
  213. $Nonce = rand(10000, 20000);
  214. $Timestamp = time();
  215. $Method = 'POST';
  216. $ExternalId = "";
  217. if (array_key_exists('externalId', $config)) {
  218. $ExternalId = $config['externalId'];
  219. }
  220. if (array_key_exists('durationSeconds', $config)) {
  221. if (!(is_integer($config['durationSeconds']))) {
  222. throw new \Exception("durationSeconds must be a int type");
  223. }
  224. }
  225. $params = array(
  226. 'SecretId' => $config['secretId'],
  227. 'Timestamp' => $Timestamp,
  228. 'RoleArn' => $RoleArn,
  229. 'Action' => $Action,
  230. 'Nonce' => $Nonce,
  231. 'DurationSeconds' => $config['durationSeconds'],
  232. 'Version' => '2018-08-13',
  233. 'RoleSessionName' => 'cos',
  234. 'Region' => $config['region'],
  235. 'ExternalId' => $ExternalId,
  236. 'Policy' => urlencode($policyStr)
  237. );
  238. $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config);
  239. $url = 'https://sts.internal.tencentcloudapi.com/';
  240. if (array_key_exists('endpoint', $config)) {
  241. $url = 'https://sts.' . $config['endpoint'];
  242. }
  243. $ch = curl_init($url);
  244. if (array_key_exists('proxy', $config)) {
  245. $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']);
  246. }
  247. curl_setopt($ch, CURLOPT_HEADER, 0);
  248. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  249. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
  250. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  251. curl_setopt($ch, CURLOPT_POST, 1);
  252. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params));
  253. $result = curl_exec($ch);
  254. if (curl_errno($ch)) $result = curl_error($ch);
  255. curl_close($ch);
  256. $result = json_decode($result, 1);
  257. if (isset($result['Response'])) {
  258. $result = $result['Response'];
  259. if (isset($result['Error'])) {
  260. throw new \Exception("get cam failed");
  261. }
  262. $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds'];
  263. }
  264. $result = $this->backwardCompat($result);
  265. return $result;
  266. } catch (\Exception $e) {
  267. if ($result == null) {
  268. $result = "error: " . $e->getMessage();
  269. } else {
  270. $result = json_encode($result);
  271. }
  272. throw new \Exception($result);
  273. }
  274. }
  275. // get policy
  276. function getPolicy($scopes)
  277. {
  278. if (!is_array($scopes)) {
  279. return null;
  280. }
  281. $statements = array();
  282. for ($i = 0, $counts = count($scopes); $i < $counts; $i++) {
  283. $actions = array();
  284. $resources = array();
  285. array_push($actions, $scopes[$i]->get_action());
  286. array_push($resources, $scopes[$i]->get_resource());
  287. $statement = array(
  288. 'action' => $actions,
  289. 'effect' => $scopes[$i]->get_effect(),
  290. 'resource' => $resources
  291. );
  292. array_push($statements, $statement);
  293. }
  294. $policy = array(
  295. 'version' => '2.0',
  296. 'statement' => $statements
  297. );
  298. return $policy;
  299. }
  300. }