我使用以下代码为我的内容创建签名网址:
var storage = require('@google-cloud/storage')();
var myBucket = storage.bucket('my-bucket');
var file = myBucket.file('my-file');
//-
// Generate a URL that allows temporary access to download your file.
//-
var request = require('request');
var config = {
action: 'read',
expires: '03-17-2025'
};
file.getSignedUrl(config, function(err, url) {
if (err) {
console.error(err);
return;
}
// The file is now available to read from the URL.
});
这将创建一个以
https://storage.googleapis.com/my-bucket/
开头的 URL
如果我将该 URL 放入浏览器中,它是可读的。
但是,我猜该 URL 是对存储桶文件的直接访问,并且没有通过我配置的 CDN。
我在文档(https://cloud.google.com/nodejs/docs/reference/storage/1.6.x/File#getSignedUrl)中看到,您可以传递 cname 选项,该选项会转换要替换的 url
https://storage.googleapis.com/my-bucket/
到我的存储桶 CDN。
但是,当我复制生成的 URL 时,服务帐户或生成的 URL 似乎无法访问该资源。
我已将 firebase 管理服务帐户添加到存储桶中,但仍然无法访问。
此外,从文档来看,CDN 签名的 URL 似乎与通过该 API 签名的 URL 有很大不同。 是否可以从 api 创建 CDN 签名网址,或者我应该按照以下说明手动创建它:https://cloud.google.com/cdn/docs/using-signed-urls?hl=en_US&_ga=2.131493069。 -352689337.1519430995#configuring_google_cloud_storage_permissions?
对于任何对该签名的节点代码感兴趣的人:
var url = 'URL of the endpoint served by Cloud CDN';
var key_name = 'Name of the signing key added to the Google Cloud Storage bucket or service';
var key = 'Signing key as urlsafe base64 encoded string';
var expiration = Math.round(new Date().getTime()/1000) + 600; //ten minutes after, in seconds
var crypto = require("crypto");
var URLSafeBase64 = require('urlsafe-base64');
// Decode the URL safe base64 encode key
var decoded_key = URLSafeBase64.decode(key);
// buILD URL
var urlToSign = url
+ (url.indexOf('?') > -1 ? "&" : "?")
+ "Expires=" + expiration
+ "&KeyName=" + key_name;
//Sign the url using the key and url safe base64 encode the signature
var hmac = crypto.createHmac('sha1', decoded_key);
var signature = hmac.update(urlToSign).digest();
var encoded_signature = URLSafeBase64.encode(signature);
//Concatenate the URL and encoded signature
urlToSign += "&Signature=" + encoded_signature;
Cloud CDN 内容分发网络与 HTTP(S) 负载平衡配合使用,将内容分发给您的用户。 您是否使用 HTTPS 负载均衡器向用户传送内容? 您可以查看此附件文档[1],了解如何使用 Google Cloud CDN 和 HTTP(S) 负载平衡以及将内容插入缓存。
[1] https://cloud.google.com/cdn/docs/overview [2] https://cloud.google.com/cdn/docs/concepts
您收到什么错误代码?您可以使用curl命令并发送带有错误代码的输出以进行进一步分析吗?
您能否确认您所做的配置满足可缓存性的要求,因为并非所有的HTTP响应都是可缓存的? Google Cloud CDN 仅缓存那些满足特定条件的响应 [3],请确认。确认后,我会做进一步调查并提供相应建议。
[3] 可缓存性:https://cloud.google.com/cdn/docs/caching#cacheability
您能否向我提供下面这两个命令的输出,这将帮助我验证这些对象是否存在权限问题?这些命令将转储对象上的所有当前权限设置。
gsutil acl get gs://[要缓存的文件的完整路径] gsutil ls -L gs://[要缓存的文件的完整路径]
有关权限的更多详细信息,请参阅此 GCP 文档 [4]
[4] 设置存储桶权限:https://cloud.google.com/storage/docs/cloud-console#_bucketpermission
不,无法从 API 创建 CDN 签名 URL
来自 Google 文档此处。 @htafoya 提供的答案似乎是合法的。 然而,我花了几个小时来思考为什么签名 URL 无法工作,因为 CDN 端点抱怨访问被拒绝。最终我发现使用
crypto
模块的代码不会产生与 gcloud compute sign-url
计算的相同的 hmac-sha1 哈希值,我仍然不知道为什么。
同时,我看到这个lib(jsSHA)非常酷,它生成的HMAC-SHA1哈希值与
gcloud
完全相同,并且它有一个简洁的API,所以我想我应该在这里发表评论,以便如果其他有同样困难的人会从中受益,这是我用来签署 gcloud cdn URL 的最终代码:
import jsSHA from 'jssha';
const url = `https://{domain}/{path}`;
const expire = Math.round(new Date().getTime() / 1000) + daySeconds;
const extendedUrl = `${url}${url.indexOf('?') > -1 ? "&" : "?"}Expires=${expire}&KeyName=${keyName}`;
// use jssha
const shaObj = new jsSHA("SHA-1", "TEXT", { hmacKey: { value: signKey, format: "B64" } });
shaObj.update(extendedUrl);
const signature = safeSign(shaObj.getHMAC('B64'));
return `${extendedUrl}&Signature=${signature}`;
工作得很好!
稍微修改了@htafoya代码,
async generateSignedUrlForCdnResource(fileName: string): Promise<string> {
const url =
this.configService.get<string>(GCP_BACKEND_BUCKET_BASE_URL) + fileName;
const base64SignedKey = this.configService.get<string>(
GCP_SIGNING_BASE_64_ENCODED_KEY,
);
const expirationTime = Date.now() + 2 * 60; // 2 minutes
const strippedUrl = url.trim();
const parsedUrl = new URL(strippedUrl);
const queryParams = new URLSearchParams(parsedUrl.search);
const expirationTimestamp = Math.floor(expirationTime);
const decodedKey = Buffer.from(base64SignedKey, 'base64url');
const urlToSign = `${strippedUrl}${queryParams.toString() ? '&' : '?'}Expires=${expirationTimestamp}&KeyName=${this.configService.get<string>(GCP_SIGNING_KEY_FILE_NAME)}`;
const hmac = crypto.createHmac('sha1', decodedKey);
hmac.update(urlToSign);
const digest = hmac.digest();
const signature = Buffer.from(digest).toString('base64url');
return `${urlToSign}&Signature=${signature}`;
}