在Firebase存储中使用函数for Firebase上传文件后,我想获取该文件的下载URL.
我有这个 :
... return bucket .upload(fromFilePath, {destination: toFilePath}) .then((err, file) => { // Get the download url of file });
目标文件有很多参数.甚至一个名字mediaLink
.但是,如果我尝试访问此链接,我会收到此错误:
匿名用户没有storage.objects.get访问对象...
有人可以告诉我如何获取公共下载Url?
谢谢
您需要通过@ google-cloud/storage NPM模块使用getSignedURL生成签名网址.
例:
const gcs = require('@google-cloud/storage')({keyFilename: 'service-account.json'}); // ... const bucket = gcs.bucket(bucket); const file = bucket.file(fileName); return file.getSignedUrl({ action: 'read', expires: '03-09-2491' }).then(signedUrls => { // signedUrls[0] contains the file's public URL });
您需要@google-cloud/storage
使用服务帐户凭据初始化,因为应用程序默认凭据是不够的.
更新:现在可以通过Firebase Admin SDK访问Cloud Storage SDK,它充当 @ google-cloud/storage 的包装器.唯一的方法是你要么:
使用特殊服务帐户启动SDK,通常通过第二个非默认实例.
或者,如果没有服务帐户,则为默认的App Engine服务帐户提供"signBlob"权限.
以下是有关如何在上传时指定下载令牌的示例:
const UUID = require("uuid-v4"); const fbId = ""; const fbKeyFile = "./YOUR_AUTH_FIlE.json"; const gcs = require('@google-cloud/storage')({keyFilename: fbKeyFile}); const bucket = gcs.bucket(`${fbId}.appspot.com`); var upload = (localFile, remoteFile) => { let uuid = UUID(); return bucket.upload(localFile, { destination: remoteFile, uploadType: "media", metadata: { contentType: 'image/png', metadata: { firebaseStorageDownloadTokens: uuid } } }) .then((data) => { let file = data[0]; return Promise.resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent(file.name) + "?alt=media&token=" + uuid); }); }
然后打电话给
upload(localPath, remotePath).then( downloadURL => { console.log(downloadURL); });
这里的关键是metadata
在metadata
option属性中嵌套了一个对象.设置firebaseStorageDownloadTokens
为uuid-v4值将告知云存储将其用作其公共身份验证令牌.
非常感谢@martemorfosis
此答案将总结在将文件上传到Google / Firebase Cloud Storage时获取下载URL的选项。共有三种下载URL:
签名的下载URL,这些URL是临时的并具有安全功能
令牌下载URL,这些URL具有永久性并具有安全功能
公共下载URL,这些URL持久且缺乏安全性
有三种获取令牌下载URL的方法。其他两个下载URL只有一种获取方式。
从Firebase存储控制台
您可以从Firebase存储控制台获取下载URL:
下载网址如下所示:
https://firebasestorage.googleapis.com/v0/b/languagetwo-cd94d.appspot.com/o/Audio%2FEnglish%2FUnited_States-OED-0%2Fabout.mp3?alt=media&token=489c48b3-23fb-4270-bd85-0a328d2808e5
第一部分是文件的标准路径。最后是令牌。此下载URL是永久性的,即即使您可以撤消它也不会过期。
从前端getDownloadURL()
该文档告诉我们使用getDownloadURL()
:
https://firebasestorage.googleapis.com/v0/b/languagetwo-cd94d.appspot.com/o/Audio%2FEnglish%2FUnited_States-OED-0%2Fabout.mp3?alt=media&token=489c48b3-23fb-4270-bd85-0a328d2808e5
这将获得与您从Firebase Storage控制台获得的下载URL相同的下载URL。这种方法很简单,但是要求您知道文件的路径,对于我的应用程序,它的路径约为300行,以实现相对简单的数据库结构。如果您的数据库很复杂,那将是一场噩梦。您可以从前端上传文件,但这会将您的凭据公开给下载您的应用程序的任何人。因此,对于大多数项目,您需要从Node后端或Google Cloud Functions上传文件,然后获取下载URL并将其与有关文件的其他数据一起保存到数据库中。
临时下载URL的getSignedUrl()
从节点后端或Google Cloud Functions易于使用getSignedUrl():
let url = await firebase.storage().ref('Audio/English/United_States-OED-' + i +'/' + $scope.word.word + ".mp3").getDownloadURL();
签名的下载URL如下所示:
https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio%2FSpanish%2FLatin_America-Sofia-Female-IBM%2Faqu%C3%AD.mp3?GoogleAccessId=languagetwo-cd94d%40appspot.gserviceaccount.com&Expires=4711305600&Signature=WUmABCZIlUp6eg7dKaBFycuO%2Baz5vOGTl29Je%2BNpselq8JSl7%2BIGG1LnCl0AlrHpxVZLxhk0iiqIejj4Qa6pSMx%2FhuBfZLT2Z%2FQhIzEAoyiZFn8xy%2FrhtymjDcpbDKGZYjmWNONFezMgYekNYHi05EPMoHtiUDsP47xHm3XwW9BcbuW6DaWh2UKrCxERy6cJTJ01H9NK1wCUZSMT0%2BUeNpwTvbRwc4aIqSD3UbXSMQlFMxxWbPvf%2B8Q0nEcaAB1qMKwNhw1ofAxSSaJvUdXeLFNVxsjm2V9HX4Y7OIuWwAxtGedLhgSleOP4ErByvGQCZsoO4nljjF97veil62ilaQ%3D%3D
签名的URL具有有效日期和长签名。命令行gsutil signurl -d的文档指出,已签名的URL是临时的:默认有效期为一小时,最大有效期为七天。
在这里,我要保证getSignedUrl永远不会说您签名的URL将在一周内过期。文档代码3-17-2025
以到期日期为准,建议您设置将来的到期年份。我的应用程序运行正常,一周后崩溃了。错误消息指出签名不匹配,不是下载URL过期。我对代码进行了各种更改,一切正常……直到一周后所有崩溃。持续了一个多月的挫败感。
使文件公开可用
您可以将文件的权限设置为公开读取,如文档所述。可以从Cloud Storage Browser或您的Node服务器完成。您可以将一个文件或目录或整个存储数据库公开。这是节点代码:
function oedPromise() {
return new Promise(function(resolve, reject) {
http.get(oedAudioURL, function(response) {
response.pipe(file.createWriteStream(options))
.on('error', function(error) {
console.error(error);
reject(error);
})
.on('finish', function() {
file.getSignedUrl(config, function(err, url) {
if (err) {
console.error(err);
return;
} else {
resolve(url);
}
});
});
});
});
}
结果将在您的Cloud Storage Browser中如下所示:
然后,任何人都可以使用标准路径下载文件:
https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3
公开文件的另一种方法是使用方法makePublic()。我一直无法使它正常工作,正确设置存储桶和文件路径非常棘手。
一个有趣的替代方法是使用访问控制列表。您可以使文件仅对您列出的用户可用,或用于authenticatedRead
使文件对从Google帐户登录的任何人可用。如果有一个选项“使用Firebase Auth登录到我的应用程序的任何人”,我将使用此选项,因为它将限制仅对我的用户的访问。
使用firebaseStorageDownloadTokens构建自己的下载URL
有几个答案描述了一个未记录的Google Storage对象属性firebaseStorageDownloadTokens
。这样,您可以告诉Storage您想要使用的令牌。您可以使用uuid
Node模块生成令牌。四行代码,您可以构建自己的下载URL,即从控制台或获得的下载URL getDownloadURL()
。四行代码是:
https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio%2FSpanish%2FLatin_America-Sofia-Female-IBM%2Faqu%C3%AD.mp3?GoogleAccessId=languagetwo-cd94d%40appspot.gserviceaccount.com&Expires=4711305600&Signature=WUmABCZIlUp6eg7dKaBFycuO%2Baz5vOGTl29Je%2BNpselq8JSl7%2BIGG1LnCl0AlrHpxVZLxhk0iiqIejj4Qa6pSMx%2FhuBfZLT2Z%2FQhIzEAoyiZFn8xy%2FrhtymjDcpbDKGZYjmWNONFezMgYekNYHi05EPMoHtiUDsP47xHm3XwW9BcbuW6DaWh2UKrCxERy6cJTJ01H9NK1wCUZSMT0%2BUeNpwTvbRwc4aIqSD3UbXSMQlFMxxWbPvf%2B8Q0nEcaAB1qMKwNhw1ofAxSSaJvUdXeLFNVxsjm2V9HX4Y7OIuWwAxtGedLhgSleOP4ErByvGQCZsoO4nljjF97veil62ilaQ%3D%3D
var webmPromise = new Promise(function(resolve, reject) {
var options = {
destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
predefinedAcl: 'publicRead',
contentType: 'audio/' + audioType,
};
synthesizeParams.accept = 'audio/webm';
var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
textToSpeech.synthesize(synthesizeParams)
.then(function(audio) {
audio.pipe(file.createWriteStream(options));
})
.then(function() {
console.log("webm audio file written.");
resolve();
})
.catch(error => console.error(error));
});
https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3
这是上下文中的代码:
const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
这不是打字错误-您必须嵌套firebaseStorageDownloadTokens
在metadata:
!
道格·史蒂文森(Doug Stevenson)指出,这firebaseStorageDownloadTokens
不是Google Cloud Storage的正式功能。您不会在任何Google文档中找到它,也无法保证它将在的未来版本中使用@google-cloud
。我喜欢,firebaseStorageDownloadTokens
因为这是获得我想要的东西的唯一方法,但是它有“气味”,使用起来不安全。
为什么不从Node获得getDownloadURL()?
正如@Clinton所写,Google应该在其中创建file.getDownloadURL()
一个方法@google-cloud/storage
(即,您的Node后端)。我想从Google Cloud Functions上传文件并获取令牌下载URL。
如果您正在使用Firebase项目,则可以在云功能中创建签名URL,而无需包含其他库或下载凭据文件.您只需启用IAM API并将角色添加到现有服务帐户(请参阅下文).
初始化管理库并获得正常的文件引用:
import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' admin.initializeApp(functions.config().firebase) const myFile = admin.storage().bucket().file('path/to/my/file')
然后,您使用生成签名的URL
myFile.getSignedUrl({action: 'read', expires: someDateObj}).then(urls => { const signedUrl = urls[0] })
确保您的Firebase服务帐户具有足够的权限来运行此帐户
转到Google API控制台并启用IAM API(https://console.developers.google.com/apis/api/iam.googleapis.com/overview)
仍然在API控制台中,转到主菜单"IAM&admin" - >"IAM"
单击"App Engine默认服务帐户"角色的编辑
单击"添加其他角色",然后添加名为"服务帐户令牌创建者"的角色
保存并等待一分钟以便传播更改
使用vanilla Firebase配置,第一次运行上述代码时,您将收到错误身份和访问管理(IAM)API尚未在项目XXXXXX中使用或被禁用..如果您按照错误消息中的链接并启用IAM API,您将收到另一个错误:需要权限iam.serviceAccounts.signBlob才能在服务帐户my-service-account上执行此操作.添加令牌创建者角色修复了第二个权限问题.
随着函数对象响应的最近更改,您可以获得将下载URL"拼接"在一起所需的一切,如下所示:
const img_url = 'https://firebasestorage.googleapis.com/v0/b/[YOUR BUCKET]/o/' + encodeURIComponent(object.name) + '?alt=media&token=' + object.metadata.firebaseStorageDownloadTokens; console.log('URL',img_url);
对于那些想知道Firebase Admin SDK serviceAccountKey.json文件应该去哪里的人.只需将其放在函数文件夹中并照常部署即可.
它仍然让我感到困惑,为什么我们不能像在Javascript SDK中那样从元数据中获取下载URL.生成最终将过期并将其保存在数据库中的URL是不可取的.
我建议在使用Cloud Storage NodeJS 1.6.x或+ predefinedAcl: 'publicRead'
上传文件时使用该选项:
const options = { destination: yourFileDestination, predefinedAcl: 'publicRead' }; bucket.upload(attachment, options);
然后,获取公共URL非常简单:
bucket.upload(attachment, options).then(result => { const file = result[0]; return file.getMetadata(); }).then(results => { const metadata = results[0]; console.log('metadata=', metadata.mediaLink); }).catch(error => { console.error(error); });
我成功使用的一种方法是firebaseStorageDownloadTokens
在完成上传后将UUID v4值设置为文件元数据中指定的键,然后按照Firebase用于生成这些URL的结构自行组装下载URL,例如:
https://firebasestorage.googleapis.com/v0/b/[BUCKET_NAME]/o/[FILE_PATH]?alt=media&token=[THE_TOKEN_YOU_CREATED]
我不知道使用这种方法有多"安全"(考虑到Firebase可能会改变将来生成下载URL的方式),但它很容易实现.
抱歉,由于缺少声誉,我无法在上面的问题上发表评论,所以我会将其包含在此答案中.
通过生成签名的Url,如上所述,但不是使用service-account.json我认为你必须使用你可以生成的serviceAccountKey.json(相应地替换YOURPROJECTID)
https://console.firebase.google.com/project/YOURPROJECTID/settings/serviceaccounts/adminsdk
例:
const gcs = require('@google-cloud/storage')({keyFilename: 'serviceAccountKey.json'}); // ... const bucket = gcs.bucket(bucket); // ... return bucket.upload(tempLocalFile, { destination: filePath, metadata: { contentType: 'image/jpeg' } }) .then((data) => { let file = data[0] file.getSignedUrl({ action: 'read', expires: '03-17-2025' }, function(err, url) { if (err) { console.error(err); return; } // handle url })
我无法评论James Daniels给出的答案,但是我认为这很重要。
像他那样提供一个签名的URL在许多情况下看起来都很糟糕,甚至有危险。根据Firebase的文档,签名的URL会在一段时间后过期,因此将其添加到您的数据库将导致在特定时间段后出现空URL
可能是误解了那里的文档,并且签名的url没有过期,因此会带来一些安全问题。每个上载文件的密钥似乎都相同。这意味着,一旦您获得一个文件的url,则只要知道文件名,某人就可以轻松访问他不应该访问的文件。
如果我误解了,那我会纠正。其他人可能应该更新上面命名的解决方案。如果我在那里错了