sts.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // 临时密钥服务例子
  2. var bodyParser = require('body-parser');
  3. var STS = require('qcloud-cos-sts');
  4. var express = require('express');
  5. var crypto = require('crypto');
  6. // 配置参数
  7. var config = {
  8. secretId: process.env.SecretId,
  9. secretKey: process.env.SecretKey,
  10. proxy: process.env.Proxy,
  11. durationSeconds: 1800,
  12. bucket: process.env.Bucket,
  13. region: process.env.Region,
  14. // 允许操作(上传)的对象前缀,可以根据自己网站的用户登录态判断允许上传的目录,例子: user1/* 或者 * 或者a.jpg
  15. // 请注意当使用 * 时,可能存在安全风险,详情请参阅:https://cloud.tencent.com/document/product/436/40265
  16. allowPrefix: '_ALLOW_DIR_/*',
  17. // 简单上传和分片,需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/14048
  18. allowActions: [
  19. // 所有 action 请看文档 https://cloud.tencent.com/document/product/436/31923
  20. // 简单上传
  21. 'name/cos:PutObject',
  22. 'name/cos:PostObject',
  23. // 分片上传
  24. 'name/cos:InitiateMultipartUpload',
  25. 'name/cos:ListMultipartUploads',
  26. 'name/cos:ListParts',
  27. 'name/cos:UploadPart',
  28. 'name/cos:CompleteMultipartUpload'
  29. ],
  30. // condition条件限定,关于 condition 的详细设置规则和COS支持的condition类型可以参考https://cloud.tencent.com/document/product/436/71306
  31. // condition:{
  32. // // 比如限制该ip才能访问cos
  33. // 'ip_equal': {
  34. // 'qcs:ip': '192.168.1.1'
  35. // }
  36. // }
  37. };
  38. // 生成带日期的随机文件名
  39. var createFileName = function (ext) {
  40. var N = (x, n) => ('000000' + x).slice(-(n || 2));
  41. var d = new Date();
  42. var ymd = d.getFullYear() + N(d.getMonth() + 1) + N(d.getDate());
  43. var hms = N(d.getHours()) + N(d.getMinutes()) + N(d.getSeconds());
  44. var r = N(Math.round((Math.random() * 1000000)), 6);
  45. var fileName = ymd + '_' + hms + '_' + r;
  46. if (ext) fileName += '.' + ext;
  47. return fileName;
  48. };
  49. // 创建临时密钥服务
  50. var app = express();
  51. app.use(bodyParser.json());
  52. // 格式一:临时密钥接口
  53. app.all('/sts', function (req, res, next) {
  54. // TODO 这里根据自己业务需要做好放行判断
  55. if (config.allowPrefix === '_ALLOW_DIR_/*') {
  56. res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
  57. return;
  58. }
  59. // 获取临时密钥
  60. var LongBucketName = config.bucket;
  61. var ShortBucketName = LongBucketName.substr(0, LongBucketName.lastIndexOf('-'));
  62. var AppId = LongBucketName.substr(LongBucketName.lastIndexOf('-') + 1);
  63. var policy = {
  64. 'version': '2.0',
  65. 'statement': [{
  66. 'action': config.allowActions,
  67. 'effect': 'allow',
  68. 'resource': [
  69. 'qcs::cos:' + config.region + ':uid/' + AppId + ':prefix//' + AppId + '/' + ShortBucketName + '/' + config.allowPrefix,
  70. ],
  71. }],
  72. };
  73. var startTime = Math.round(Date.now() / 1000);
  74. STS.getCredential({
  75. secretId: config.secretId,
  76. secretKey: config.secretKey,
  77. proxy: config.proxy,
  78. region: config.region,
  79. durationSeconds: config.durationSeconds,
  80. policy: policy,
  81. }, function (err, tempKeys) {
  82. if (tempKeys) tempKeys.startTime = startTime;
  83. res.send(err || tempKeys);
  84. });
  85. });
  86. // // 格式二:临时密钥接口,支持细粒度权限控制
  87. // // 判断是否允许获取密钥
  88. // var allowScope = function (scope) {
  89. // var allow = (scope || []).every(function (item) {
  90. // return config.allowActions.includes(item.action) &&
  91. // item.bucket === config.bucket &&
  92. // item.region === config.region &&
  93. // (item.prefix || '').startsWith(config.allowPrefix);
  94. // });
  95. // return allow;
  96. // };
  97. // app.all('/sts-scope', function (req, res, next) {
  98. // var scope = req.body;
  99. //
  100. // // TODO 这里根据自己业务需要做好放行判断
  101. // if (config.allowPrefix === '_ALLOW_DIR_/*') {
  102. // res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
  103. // return;
  104. // }
  105. // // TODO 这里可以判断 scope 细粒度控制权限
  106. // if (!scope || !scope.length || !allowScope(scope)) return res.send({error: 'deny'});
  107. //
  108. // // 获取临时密钥
  109. // var policy = STS.getPolicy(scope);
  110. // var startTime = Math.round(Date.now() / 1000);
  111. // STS.getCredential({
  112. // secretId: config.secretId,
  113. // secretKey: config.secretKey,
  114. // proxy: config.proxy,
  115. // durationSeconds: config.durationSeconds,
  116. // policy: policy,
  117. // }, function (err, tempKeys) {
  118. // if (tempKeys) tempKeys.startTime = startTime;
  119. // res.send(err || tempKeys);
  120. // });
  121. // });
  122. //
  123. // // 用于 PostObject 签名保护
  124. // app.all('/post-policy', function (req, res, next) {
  125. // var query = req.query;
  126. // var ext = query.ext;
  127. // var key = 'images/' + createFileName(ext);
  128. // var now = Math.round(Date.now() / 1000);
  129. // var exp = now + 900;
  130. // var qKeyTime = now + ';' + exp;
  131. // var qSignAlgorithm = 'sha1';
  132. // var policy = JSON.stringify({
  133. // 'expiration': new Date(exp * 1000).toISOString(),
  134. // 'conditions': [
  135. // // {'acl': query.ACL},
  136. // // ['starts-with', '$Content-Type', 'image/'],
  137. // // ['starts-with', '$success_action_redirect', redirectUrl],
  138. // // ['eq', '$x-cos-server-side-encryption', 'AES256'],
  139. // {'q-sign-algorithm': qSignAlgorithm},
  140. // {'q-ak': config.secretId},
  141. // {'q-sign-time': qKeyTime},
  142. // {'bucket': config.bucket},
  143. // {'key': key},
  144. // ]
  145. // });
  146. //
  147. // // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
  148. // // 步骤一:生成 SignKey
  149. // var signKey = crypto.createHmac('sha1', config.secretKey).update(qKeyTime).digest('hex');
  150. //
  151. // // 步骤二:生成 StringToSign
  152. // var stringToSign = crypto.createHash('sha1').update(policy).digest('hex');
  153. //
  154. // // 步骤三:生成 Signature
  155. // var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex');
  156. //
  157. // console.log(policy);
  158. // res.send({
  159. // bucket: config.bucket,
  160. // region: config.region,
  161. // key: key,
  162. // policyObj: JSON.parse(policy),
  163. // policy: Buffer.from(policy).toString('base64'),
  164. // qSignAlgorithm: qSignAlgorithm,
  165. // qAk: config.secretId,
  166. // qKeyTime: qKeyTime,
  167. // qSignature: qSignature,
  168. // // securityToken: securityToken, // 如果使用临时密钥,要返回在这个资源 sessionToken 的值
  169. // });
  170. // });
  171. app.all('*', function (req, res, next) {
  172. res.send({code: -1, message: '404 Not Found'});
  173. });
  174. // 启动签名服务
  175. app.listen(3000);
  176. console.log('app is listening at http://127.0.0.1:3000');