[node.js] Firebase 용 Cloud Functions로 업로드 된 파일에서 다운로드 URL 가져 오기

Firebase 용 함수로 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 을 사용하여 서명 된 URL을 생성해야 합니다.

예:

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함께 서비스 계정 자격 증명 응용 프로그램의 기본 자격 증명이 충분하지 않으므로.

업데이트 : 이제 @ google-cloud / storage 의 래퍼 역할을하는 Firebase Admin SDK를 통해 Cloud Storage SDK에 액세스 할 수 있습니다 . 유일한 방법은 다음과 같은 경우입니다.

  1. 일반적으로 기본이 아닌 두 번째 인스턴스를 통해 특수 서비스 계정으로 SDK를 초기화합니다.
  2. 또는 서비스 계정없이 기본 App Engine 서비스 계정에 ‘signBlob’권한을 부여합니다.

답변

다음은 업로드시 다운로드 토큰을 지정하는 방법에 대한 예입니다.

const UUID = require("uuid-v4");

const fbId = "<YOUR APP ID>";
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);
  });

여기서 핵심 metadatametadata옵션 속성 내에 중첩 된 객체 가 있다는 것입니다 . firebaseStorageDownloadTokensuuid-v4 값으로 설정 하면 Cloud Storage가이를 공개 인증 토큰으로 사용하도록 지시합니다.

@martemorfosis 덕분에


답변

이 답변은 Google / Firebase Cloud Storage에 파일을 업로드 할 때 다운로드 URL을 가져 오는 옵션을 요약합니다. 다운로드 URL에는 세 가지 유형이 있습니다.

  1. 임시적이고 보안 기능이있는 서명 된 다운로드 URL
  2. 영구적이고 보안 기능이있는 토큰 다운로드 URL
  3. 영구적이고 보안이 부족한 공개 다운로드 URL

토큰 다운로드 URL을 얻는 방법에는 세 가지가 있습니다. 다른 두 개의 다운로드 URL에는이를 가져올 수있는 방법이 하나뿐입니다.

Firebase 저장소 콘솔에서

Firebase 저장소 콘솔에서 다운로드 URL을 가져올 수 있습니다.

여기에 이미지 설명 입력

다운로드 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():

let url = await firebase.storage().ref('Audio/English/United_States-OED-' + i +'/' + $scope.word.word + ".mp3").getDownloadURL();

Firebase 저장소 콘솔에서 얻을 수있는 것과 동일한 다운로드 URL을 가져옵니다. 이 방법은 쉽지만 비교적 간단한 데이터베이스 구조를 위해 내 앱에서 약 300 줄의 코드 인 파일 경로를 알고 있어야합니다. 데이터베이스가 복잡하다면 악몽이 될 것입니다. 프런트 엔드에서 파일을 업로드 할 수 있지만이 경우 앱을 다운로드하는 모든 사람에게 자격 증명이 노출됩니다. 따라서 대부분의 프로젝트에서 노드 백엔드 또는 Google Cloud Functions에서 파일을 업로드 한 다음 다운로드 URL을 가져 와서 파일에 대한 다른 데이터와 함께 데이터베이스에 저장하려고합니다.

임시 다운로드 URL 용 getSignedUrl ()

getSignedUrl () 은 Node 백엔드 또는 Google Cloud Functions에서 사용하기 쉽습니다.

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

서명 된 다운로드 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은 임시적입니다. 기본 만료 시간은 1 시간이고 최대 만료 시간은 7 일입니다.

여기서 getSignedUrl 은 서명 된 URL이 1 주일 후에 만료된다는 사실을 결코 말하지 않는다는 사실을 폭언 할 것입니다. 문서 코드에는 3-17-2025만료 날짜가 있으므로 향후 만료 연도를 설정할 수 있음을 나타냅니다. 내 앱은 완벽하게 작동했지만 일주일 후 충돌했습니다. 오류 메시지는 다운로드 URL이 만료 된 것이 아니라 서명이 일치하지 않는다는 내용입니다. 나는 내 코드를 다양하게 변경했고 모든 것이 작동했다. 이것은 한 달이 넘는 좌절감 동안 계속되었습니다.

파일을 공개적으로 사용 가능하게 만들기

문서에 설명 된대로 파일에 대한 권한을 공개 읽기로 설정할 수 있습니다 . 이는 Cloud Storage 브라우저 또는 노드 서버에서 수행 할 수 있습니다. 하나의 파일을 공개하거나 디렉토리 또는 전체 스토리지 데이터베이스를 만들 수 있습니다. 다음은 노드 코드입니다.

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

결과는 Cloud Storage 브라우저에서 다음과 같이 표시됩니다.

여기에 이미지 설명 입력

그러면 누구나 표준 경로를 사용하여 파일을 다운로드 할 수 있습니다.

https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3

파일을 공개하는 또 다른 방법은 makePublic () 메서드를 사용하는 것 입니다. 이 작업을 수행 할 수 없었고 버킷 및 파일 경로를 올바르게 지정하는 것이 까다 롭습니다.

흥미로운 대안은 액세스 제어 목록 을 사용하는 것 입니다. 목록에 추가 한 사용자 만 파일을 사용할 수 있도록하거나 authenticatedReadGoogle 계정으로 로그인 한 모든 사용자가 파일을 사용할 수 있도록하는 데 사용할 수 있습니다. “Firebase Auth를 사용하여 내 앱에 로그인 한 모든 사람”옵션이있는 경우이 옵션을 사용하면 내 사용자에게만 액세스 권한이 제한됩니다.

firebaseStorageDownloadTokens로 나만의 다운로드 URL 구축

문서화되지 않은 Google Storage 객체 속성에 대한 몇 가지 답변이 있습니다 firebaseStorageDownloadTokens. 이를 통해 사용하려는 토큰을 Storage에 알릴 수 있습니다. uuidNode 모듈 로 토큰을 생성 할 수 있습니다 . 네 줄의 코드를 사용하면 콘솔 또는 .NET에서 가져온 것과 동일한 다운로드 URL 인 고유 한 다운로드 URL을 만들 수 있습니다 getDownloadURL(). 네 줄의 코드는 다음과 같습니다.

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: { firebaseStorageDownloadTokens: uuid }
https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);

컨텍스트의 코드는 다음과 같습니다.

var webmPromise = new Promise(function(resolve, reject) {
  var options = {
    destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
    contentType: 'audio/' + audioType,
    metadata: {
      metadata: {
        firebaseStorageDownloadTokens: uuid,
      }
    }
  };

      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() {
        resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);
      })
      .catch(error => console.error(error));
});

그것은 오타가 아닙니다 .!의 firebaseStorageDownloadTokens이중 레이어에 중첩해야합니다 metadata:.

Doug Stevenson은 이것이 firebaseStorageDownloadTokens공식적인 Google Cloud Storage 기능이 아니라고 지적했습니다 . Google 문서에서 찾을 수 없으며의 향후 버전에 포함될 것이라는 약속도 없습니다 @google-cloud. 내가 원하는 firebaseStorageDownloadTokens것을 얻을 수있는 유일한 방법이기 때문에 좋아 하지만 사용하기에 안전하지 않다는 “냄새”가 있습니다.

Node에 getDownloadURL ()이없는 이유는 무엇입니까?

@Clinton이 썼 듯이 Google은 (즉, 노드 백엔드) file.getDownloadURL()에서 메소드를 만들어야합니다 @google-cloud/storage. Google Cloud Functions에서 파일을 업로드하고 토큰 다운로드 URL을 받고 싶습니다.


답변

함수 객체 응답 의 최근 변경으로 다음 과 같이 다운로드 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 프로젝트에서 작업하는 경우 다른 라이브러리를 포함하거나 사용자 인증 정보 파일을 다운로드하지 않고도 Cloud Function에서 서명 된 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 서비스 계정에이 작업을 실행할 수있는 충분한 권한이 있는지 확인하세요.

  1. Google API 콘솔로 이동하여 IAM API ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview )를 활성화합니다.
  2. API 콘솔에서 주 메뉴 “IAM 및 관리자”-> “IAM”으로 이동합니다.
  3. ‘App Engine 기본 서비스 계정’역할에 대한 수정을 클릭합니다.
  4. “다른 역할 추가”를 클릭하고 “서비스 계정 토큰 생성자”라는 역할을 추가합니다.
  5. 저장하고 변경 사항이 전파 될 때까지 잠시 기다리십시오.

바닐라 Firebase 구성을 사용하는 경우 위 코드를 처음 실행하면 ID 및 액세스 관리 (IAM) API가 이전에 프로젝트 XXXXXX에서 사용되지 않았거나 사용 중지되었다는 오류 가 표시됩니다. . 오류 메시지의 링크를 따라 IAM API를 활성화하면 또 다른 오류가 발생합니다. 서비스 계정 my-service-account에서이 작업을 수행하려면 권한 iam.serviceAccounts.signBlob이 필요합니다 . 토큰 생성자 역할을 추가하면이 두 번째 권한 문제가 해결됩니다.


답변

내가 성공적으로 사용하는 한 가지 방법은 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을 생성하는 방법을 변경할 수 있다는 점을 감안할 때) 구현하기 쉽습니다.


답변

Firebase Admin SDK serviceAccountKey.json 파일이 어디로 이동해야하는지 궁금한 분들을 위해. functions 폴더에 넣고 평소대로 배포하십시오.

Javascript SDK 에서처럼 메타 데이터에서 다운로드 URL을 가져올 수없는 이유는 여전히 당황 스럽습니다. 결국 만료 될 URL을 생성하여 데이터베이스에 저장하는 것은 바람직하지 않습니다.