IBM Cloud

IBM Storage 预签名 URL

IBM Storage 提供了预签名URL的功能,该功能会创建一个临时链接,可用于共享公共的文件。该URL,还可以设定有效期。创建预签名 URL 的最简单方法是使用 AWS CLI ,还可以编程实现,比如Python,java,Nodejs。

官方文档:

https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-presign-url#presign-url-get

Nodejs 代码:

https://github.com/gustavares/cos-tutorial


下面以Nodejs为例子,介绍一下步骤。
  • 在IBM CLoud上创建Storage服务,以及创建相应的Bucket,并且往Bucket中上传一个测试文件。(下面例子中上传了一个IOS.Mp4文件。)
  • 创建服务凭证,添加HMAC认证。创建完,以后可以看到相应的认证信息。
  • 创建一个Nodejs工程。
package.json

{
  "name": "presigned",
  "version": "1.0.0",
  "description": "presigned",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.4",
    "express-handlebars": "^3.1.0",
    "request": "^2.88.2",
    "ibm-cos-sdk": "^1.9.0"
  }
}
Server.js

"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
var express = require("express");
var bodyParser = require('body-parser');
var path = require("path");
var request = require('request');
var app = express();
const AWS = require('ibm-cos-sdk');

const config = {
  endpoint: 'https://s3.au-syd.cloud-object-storage.appdomain.cloud/',
  apiKeyId: '11sG2RjQgHFDP1kBXkQ2ndfJ2jmLxA4753oHyxohl4bO',
  ibmAuthEndpoint: 'https://iam.cloud.ibm.com/identity/token',
  serviceInstanceId: 'crn:v1:bluemix:public:cloud-object-storage:global:a/a5b79a1c10354a3e8286560d97b7a989:f88885c9-95f0-40f5-b1ef-e9c87062d3ee::',
  credentials: new AWS.Credentials(
    "9d433db78aec4b6e90514a11274961fa",
    "08c85bc1b6a000d2f32ab8b5a05f664e9142102164ad61a6",
    null
),
  signatureVersion: 'v4'
};

const cos = new AWS.S3(config);

app.use(bodyParser.json());

app.use(express.static(path.resolve(__dirname, './')));



app.post('/getPresignedUrl', async function (req, res) {

  const url = await getPresignedUrl('jretest', 'iOS.MP4', 'getObject')
  return res.status(200).json({ url });
});

async function getPresignedUrl(bucket, fileName, operation) {
  console.log("begin");
  const url = await cos.getSignedUrl(operation, {
      Bucket: bucket,
      Key: fileName,
      Expires:9000
  }); 
  return url;
}


var router = express.Router();
var serverPort = process.env.PORT || 8000;
var server = app.listen(serverPort, function () {
  console.log("Server Start");
});
server.setTimeout(1200000)
Server.js

"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
var express = require("express");
var bodyParser = require('body-parser');
var path = require("path");
var request = require('request');
var app = express();
const AWS = require('ibm-cos-sdk');

const config = {
  endpoint: 'https://s3.au-syd.cloud-object-storage.appdomain.cloud/',
  apiKeyId: 'xxxx11sG2xxxxDP1kBXkQxxxxxxxxxxxxx',
  ibmAuthEndpoint: 'https://iam.cloud.ibm.com/identity/token',
  serviceInstanceId: 'crn:v1:bluemix:public:cloud-object-storage:global:a/xxxxx:f8xxxxx-95f0-xxxxxxxe::',
  credentials: new AWS.Credentials(
    "xxx43xxxx78axxxxxxx",
    "xxxxxxxxxxxx66xxxxxxxx",
    null
),
  signatureVersion: 'v4'
};

const cos = new AWS.S3(config);
app.use(bodyParser.json());
app.use(express.static(path.resolve(__dirname, './')));


app.post('/getPresignedUrl', async function (req, res) {

  const url = await getPresignedUrl('testbucket', 'iOS.MP4', 'getObject')
  return res.status(200).json({ url });
});

// bucket:Storage的bucket名字
// fileName:bucket中的文件名
// operation:操作 putObject 和 getObject
// Expires 有效期间 单位是秒
async function getPresignedUrl(bucket, fileName, operation) {
  console.log("begin");
  const url = await cos.getSignedUrl(operation, {
      Bucket: bucket,
      Key: fileName,
      Expires:9000
  }); 
  return url;
}


var router = express.Router();
var serverPort = process.env.PORT || 8000;
var server = app.listen(serverPort, function () {
  console.log("Server Start");
});
server.setTimeout(1200000)

getSignedUrl更多的参数信息可以参照下面的链接:https://ibm.github.io/ibm-cos-sdk-js/AWS/S3.html#getSignedUrl-property

  • 启动Server,我们用RESTClient做一下测试。可以看到确实生成了,一个临时的URL

因为我们的Bucket文件是个视频文件,现在我们试着在HTML中播放一下这个文件。
Html代码


<html>
<head>
  <script>

    function jumpVideo() {
      var videoPlayer = document.getElementById("videoPlayer");
      videoPlayer.currentTime = 50
      videoPlayer.crossOrigin = 'anonymous';
    }

    function copyImage() {

      var videoPlayer = document.getElementById("videoPlayer");
      var image = document.getElementById("imagesrc");
      var canvas = document.createElement("canvas");
      canvas.width = videoPlayer.videoWidth * 1;
      canvas.height = videoPlayer.videoHeight * 1;
      canvas.getContext('2d')
        .drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
      image.src = canvas.toDataURL('image/png');

    }

  </script>
</head>

<body>
  <div>
    <video id="videoPlayer" width="586px" height="341px" controls="true"
      src="https://xxxx.s3.au-syd.cloud-object-storage.appdomain.cloud/iOS.MP4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=9d433db78aec4b6e90514a11274961fa%2F20210622%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210622T130122Z&X-Amz-Expires=9000&X-Amz-Signature=0c82403ffbb962357c10d64471094fd1a99905a529fe2a303f60e5e29783136f&X-Amz-SignedHeaders=host"
      crossorigin="anonymous"></video>
  </div>
  <button onclick="jumpVideo()">click</button>
  <button onclick="copyImage()">copyImage</button>
  <img id="imagesrc" />
</body>

</html>

这时会发现一个问题,我们这个Html有两个功能。1 播放视频 2 视频截图。

这个例子用原生的video标签播放视频,当video标签中不加【crossorigin=”anonymous”】时,视频是可以正常播放的,但是截图时【canvas.toDataURL(‘image/png’);】会报下面这个错误。

然后我们给视频的video标签中加上【crossorigin=”anonymous”】,会发现视频又播放不了了。

产生这个问题的原因是因为,IBM Storage Bucket中存储的对象默认时不支持跨域的,如果需要跨越,需要手动配置一下。

IBM Storage CORS跨域配置如下:

官方guide如下:

https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-compatibility-api-bucket-operations

可以看到操作存储区可以使用,IBM Cloud Cli,Curl, AWS CLI 等等。这里我们使用IBM Cloud Cli 做为例子。

  • 通过sso 登录IBM Cloud。
ibmcloud login --sso
  • 选择资源组
ibmcloud target -g xxxx(资源组的名字)
  • 在本地准备CORS的配置文件
{
"CORSRules": [
{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET", "POST", "PUT", "DELETE", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag", "x-cos-acl", "x-cos-version-id", "x-cos-delete-marker", "x-cos-server-side-encryption"]
}
]
}
  • 切换到配置文件所在的路径,执行下面的命令。
cd /Users/xxxxx/Desktop/
ibmcloud cos put-bucket-cors --bucket xxx(bucket的名字) --cors-configuration file://presigned
  • CORS配置成功以后,可以用下面的命令查询。
ibmcloud cos get-bucket-cors --bucket xxxx(bucket名字)
  • 删除Bucket的CORS配置。删除的时候没有找到IBM Cloud CLI命令,这里面通过CURL命令来删除。具体命令可以参考guide:https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-curl
curl -X "DELETE" "https://s3.au-syd.cloud-object-storage.appdomain.cloud/xxxx?cors" -H "Authorization: bearer eyxxxxx"
  • 这里面用到了 bearer token,下面的例子是通过Rest API获取Token。
// apiKey 可以在服务凭证里查询到
POST url:https://iam.cloud.ibm.com/identity/token?apikey=xxxxxxxxx&response_type=cloud_iam&grant_type=urn:ibm:params:oauth:grant-type:apikey

Header Accept:application/jsonHeader 
              Content-Type:application/x-www-form-urlencoded
最后,当Storage的跨域配置好以后,我们通过url访问Storage的文件时,会发现Response里面有下面的Header了。