Obter o URL de download do arquivo enviado com o Cloud Functions for Firebase

Depois de fazer o upload de um arquivo no Firebase Storage com o Functions for Firebase, eu gostaria de obter o URL de download do arquivo.

Eu tenho isto :

... return bucket .upload(fromFilePath, {destination: toFilePath}) .then((err, file) => { // Get the download url of file }); 

O arquivo object tem muitos parâmetros. Até mesmo um chamado mediaLink . No entanto, se eu tentar acessar esse link, recebo este erro:

Usuários anônimos não têm o access storage.objects.get ao object …

Alguém pode me dizer como obter o URL de download público?

Obrigado

Você precisará gerar um URL assinado usando getSignedURL por meio do módulo NPM @ google-cloud / storage .

Exemplo:

 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 }); 

Você precisará inicializar @google-cloud/storage com as credenciais da sua conta de serviço, pois as credenciais padrão do aplicativo não serão suficientes.

ATUALIZAÇÃO : agora, o SDK do Cloud Storage pode ser acessado por meio do Firebase Admin SDK, que funciona como um wrapper em torno de @ google-cloud / storage. Você ainda terá que iniciar o SDK com uma conta de serviço, geralmente por meio de uma segunda instância não padrão.

Veja um exemplo de como especificar o token de download no upload:

 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); }); } 

então ligue com

 upload(localPath, remotePath).then( downloadURL => { console.log(downloadURL); }); 

A principal coisa aqui é que existe um object de metadata nested dentro da propriedade de opção de metadata . A configuração do firebaseStorageDownloadTokens como um valor uuid-v4 dirá ao Cloud Storage para usá-lo como seu token de autenticação público.

Muito obrigado a @martemorfosis

Um método que estou usando com sucesso é definir um valor de UUID v4 para uma chave chamada firebaseStorageDownloadTokens nos metadados do arquivo depois que ele terminar de enviar e depois montar o URL de download seguindo a estrutura que o Firebase usa para gerar essas URLs, por exemplo:

 https://firebasestorage.googleapis.com/v0/b/[BUCKET_NAME]/o/[FILE_PATH]?alt=media&token=[THE_TOKEN_YOU_CREATED] 

Não sei quanto “seguro” é usar esse método (já que o Firebase pode alterar a forma como ele gera as URLs de download no futuro), mas é fácil de implementar.

Para aqueles que querem saber onde o arquivo serviceAccountKey.json do Firebase Admin SDK deve ir. Basta colocá-lo na pasta de funções e implantar como de costume.

Ainda me deixa perplexo porque não podemos simplesmente obter o URL de download dos metadados, como fazemos no Javascript SDK. Gerar uma URL que acabará por expirar e salvá-la no database não é desejável.

Com as mudanças recentes na resposta do object de funções, você pode obter tudo o que precisa para “unir” o URL de download da seguinte forma:

  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); 

Desculpe, mas eu não posso postar um comentário para sua pergunta acima por causa da falta de reputação, então vou incluí-lo nesta resposta.

Faça como indicado acima, gerando um URL assinado, mas em vez de usar o service-account.json, eu acho que você tem que usar o serviceAccountKey.json que você pode gerar em (substitua YOURPROJECTID de acordo)

https://console.firebase.google.com/project/YOURPROJECTID/settings/serviceaccounts/adminsdk

Exemplo:

 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 }) 

Sugiro usar a opção predefinedAcl: 'publicRead' ao fazer o upload de um arquivo com o Cloud Storage NodeJS 1.6.x :

 const options = { destination: yourFileDestination, predefinedAcl: 'publicRead' }; bucket.upload(attachment, options); 

Então, obter o URL público é tão simples quanto:

 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); }); 

Isso funciona se você precisar apenas de um arquivo público com um URL simples. Observe que isso pode anular as regras de armazenamento do Firebase.

 bucket.upload(file, function(err, file) { if (!err) { //Make the file public file.acl.add({ entity: 'allUsers', role: gcs.acl.READER_ROLE }, function(err, aclObject) { if (!err) { var URL = "https://storage.googleapis.com/[your bucket name]/" + file.id; console.log(URL); } else { console.log("Failed to set permissions: " + err); } }); } else { console.log("Upload failed: " + err); } }); 

Não posso comentar a resposta que James Daniels deu, mas acho que é muito importante ler.

Dando uma URL assinada Como ele fez parece para muitos casos muito ruim e possível Perigoso . De acordo com a documentação do Firebase, o URL assinado expira após algum tempo, portanto, adicioná-lo ao seu database levará a um URL vazio após um determinado período de tempo

Pode ser que tenha entendido mal a Documentação e o URL assinado não expire, o que teria alguns problemas de segurança como resultado. A chave parece ser a mesma para todos os arquivos enviados. Isso significa que, quando você tiver o URL de um arquivo, alguém poderá acessar facilmente os arquivos que ele não deve acessar, apenas conhecendo seus nomes.

Se eu não entendi isso, então eu faria para ser corrigido. Outra pessoa provavelmente deve atualizar a solução acima mencionada. Se eu posso estar errado lá

Para quem está usando o Firebase SDK e o admin.initializeApp :

1 – Gere uma chave privada e coloque na pasta / functions.

2 – Configure seu código da seguinte maneira:

 const serviceAccount = require('../../serviceAccountKey.json'); try { admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) })); } catch (e) {} 

Documentação

O try / catch é porque estou usando um index.js que importa outros arquivos e cria uma function para cada arquivo. Se você estiver usando um único arquivo index.js com todas as funções, deverá estar ok com admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) })); .