Node.js 使用NodeJS为谷歌云存储创建签名URL
我正试图为谷歌云存储中私人存储的文件创建签名;这样我就可以分发一个有时间限制的链接 目前正在这样做,它使签名太短。。。我哪里做错了Node.js 使用NodeJS为谷歌云存储创建签名URL,node.js,google-cloud-storage,sha,Node.js,Google Cloud Storage,Sha,我正试图为谷歌云存储中私人存储的文件创建签名;这样我就可以分发一个有时间限制的链接 目前正在这样做,它使签名太短。。。我哪里做错了 var crypto = require("crypto"); var ttl = new Date().getTime() + 3600; var id = 'the_target_file.txt'; var bucketName = 'bucket_name'; var POLICY_JSON = "GET\n" + "\n" + "\n" + ttl +
var crypto = require("crypto");
var ttl = new Date().getTime() + 3600;
var id = 'the_target_file.txt';
var bucketName = 'bucket_name';
var POLICY_JSON = "GET\n" + "\n" + "\n" + ttl + "\n" + '/' + bucketName + '/' + id;
// stringify and encode the policy
var stringPolicy = JSON.stringify(POLICY_JSON);
var base64Policy = Buffer(stringPolicy, "utf-8").toString("base64");
// sign the base64 encoded policy
var privateKey = "MY_PRIVATE_KEY";
var sha256 = crypto.createHmac("sha256", privateKey);
var signature = sha256.update(new Buffer(base64Policy, "utf-8")).digest("base64");
console.log ( signature );
意识到我做错了什么。。。我正在对策略字符串进行哈希运算,而不是对其进行签名。 下面的代码现在为我提供了正确的输出
var crypto = require("crypto");
var fs = require("fs");
var expiry = new Date().getTime() + 3600;
var key = 'the_target_file';
var bucketName = 'bucket_name';
var accessId = 'my_access_id';
var stringPolicy = "GET\n" + "\n" + "\n" + expiry + "\n" + '/' + bucketName + '/' + key;
var privateKey = fs.readFileSync("gcs.pem","utf8");
var signature = encodeURIComponent(crypto.createSign('sha256').update(stringPolicy).sign(privateKey,"base64"));
var signedUrl = "https://" + bucketName + ".commondatastorage.googleapis.com/" + key +"?GoogleAccessId=" + accessId + "&Expires=" + expiry + "&Signature=" + signature;
console.log(signedUrl);
为了完整起见。。。下面是一个PHP版本,它做了同样的事情,我用它来检查我的结果
$expiry = time() + 3600;
$key = 'the_target_file';
$bucketName = 'bucket_name';
$accessId = 'my_access_id';
$stringPolicy = "GET\n\n\n".$expiry."\n/".$bucketName."/".$key;
$fp = fopen('gcs.pem', 'r');
$priv_key = fread($fp, 8192);
fclose($fp);
$pkeyid = openssl_get_privatekey($priv_key,"password");
if (openssl_sign( $stringPolicy, $signature, $pkeyid, 'sha256' )) {
$signature = urlencode( base64_encode( $signature ) );
echo 'https://'.$bucketName.'.commondatastorage.googleapis.com/'.
$key.'?GoogleAccessId='.$accessId.'&Expires='.$expiry.'&Signature='.$signature;
}
现在有一个用于获取签名URL的API/模块 模块:
API文档: 范例
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' // this could also include time (MM-DD-YYYYTHH:MM:SSZ)
};
file.getSignedUrl(config, function(err, url) {
if (err) {
console.error(err);
return;
}
// The file is now available to read from this URL.
request(url, function(err, resp) {
// resp.statusCode = 200
});
});
假设这个问题是签署由google bucket后端支持的CDN url,这里是对我有效的(上面的代码对我无效) 选项和签名函数调用:
const signUrlOptions = {
expires: '' + new Date().getTime() + 3600, // one hour
keyName: '_SIGNING_KEY_NAME_', // URL signing key name (the one one you created in the CDN backend bucket)
keyBase64: '_SIGNING_KEY_BASE64_', // the URL signing key base64 content (base64-encoded, 128-bit value, ~24 characters)
baseUrl: '_CDN_BASE_URL_' // your base CDN URL (can be IP http://123.... when dev env or https://cdn_dns_name or https dns name)
}
const signedUrl = signCdnUrl('demo.png', signedUrlOptions);
签名功能:
import { createHmac } from 'crypto';
const BASE64_REPLACE = { '+': '-', '/': '_', '=': '' };
export function signCdnUrl(fileName, opts) {
// URL to sign
const urlToSign = `${opts.baseUrl}/${fileName}?Expires=${opts.expires}&KeyName=${opts.keyName}`;
// Compute signature
const keyBuffer = Buffer.from(opts.keyBase64, 'base64');
let signature = createHmac('sha1', keyBuffer).update(urlToSign).digest('base64');
signature = signature.replace(/[+/=]/g, c => (<any>BASE64_REPLACE)[c]); // might be a better way
// Add signature to urlToSign and return signedUrl
return urlToSign + `&Signature=${signature}`;
}
从“crypto”导入{createHmac};
const BASE64_REPLACE={'+':'-','/':'''''.','=':'''.};
导出函数signCdnUrl(文件名,选项){
//要签名的URL
const urlToSign=`${opts.baseUrl}/${fileName}?Expires=${opts.Expires}&KeyName=${opts.KeyName}`;
//计算签名
const keyBuffer=Buffer.from(opts.keyBase64,'base64');
让signature=createHmac('sha1',keyBuffer.).update(urlToSign).digest('base64');
signature=signature.replace(//[+/=]/g,c=>(BASE64_replace)[c]);//可能是更好的方法
//向urlToSign添加签名并返回签名URL
返回urlToSign+`&Signature=${Signature}`;
}
希望这有帮助。不知何故,google cloud doc没有一个nodejs示例,而文件.getSignedUrl()会给混合带来混乱,因为它似乎与CDN URL签名无关
注:
注意:可能希望将base64->buffer work作为opts.keyBuffer移动到调用方
如果nodejs
@googlecloud/storage
库已经是您项目的一部分,那么最好的方法就是使用它。下面的代码是google storage sdk针对nodejs的文档
npm安装@googlecloud/storage
function main(bucketName = 'you_bucket_name', filename = 'your_file_path_without_bucket_name') {
const {Storage} = require('@google-cloud/storage');
// Creates a client (Parameters not required if you are already in GCP environment)
const storage = new Storage({
projectId: 'your_project_id',
keyFilename: './json_key_path_for_some_service_account.json'
});
async function generateV4ReadSignedUrl() {
// These options will allow temporary read access to the file
const options = {
version: 'v4',
action: 'read',
expires: Date.now() + 15 * 60 * 1000, // 15 minutes
};
// Get a v4 signed URL for reading the file
const [url] = await storage
.bucket(bucketName)
.file(filename)
.getSignedUrl(options);
console.log('Generated GET signed URL:');
console.log(url);
console.log('You can use this URL with any user agent, for example:');
console.log(`curl '${url}'`);
}
generateV4ReadSignedUrl().catch(console.error);
// [END storage_generate_signed_url_v4]
}
main(...process.argv.slice(2));
如何缩短有效期。伙计,这就是为什么我还是这么做的原因。⭐️什么是
var accessId='my_access_id'代码>?很好的例子!一个小提示-在php 3600中是秒,而在js 3600中是毫秒,因为javascript的getTime()
返回毫秒。我注意到这里没有secretAccessKey,我认为这里不再需要它了?这似乎只是为bucket访问创建链接,而不是为CDN创建链接。为CDN添加cname选项仍然不允许服务帐户。这看起来是对以前复杂需求的一个非常方便的抽象。在这种情况下,什么用于对URL进行签名?值得注意的是,您也可以使用MM-DD-yyyyth:MM:SSZ格式对到期时间进行签名-分数秒似乎会导致此错误,因此请确保您的字符串在“Z”之前不包含小数和/或小数部分秒