Firebase 용 Cloud Functions로 업로드 된 파일에서 다운로드 URL 가져 오기


124

Firebase 용 함수로 Firebase 저장소에 파일을 업로드 한 후 파일의 다운로드 URL을 가져오고 싶습니다.

나는 이것을 가지고있다 :

...

return bucket
    .upload(fromFilePath, {destination: toFilePath})
    .then((err, file) => {

        // Get the download url of file

    });

개체 파일에는 많은 매개 변수가 있습니다. 이름이 mediaLink. 그러나이 링크에 액세스하려고하면이 오류가 발생합니다.

익명 사용자에게는 storage.objects.get 액세스 권한이 없습니다.

누군가 공개 다운로드 URL을 얻는 방법을 알려줄 수 있습니까?

감사합니다


함수에서 사용 가능한 데이터에서 URL을 재구성하는 이 게시물 도 참조하십시오 .
Kato

답변:


133

@ 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'권한을 부여합니다.

74
이건 이상해. Firebase Android, iOS 및 웹 SDK를 사용할 때 저장소 참조에서 다운로드 URL을 쉽게 가져올 수 있습니다. 관리자 일 때 쉽지 않은 이유는 무엇입니까? 추신 : gcs를 초기화하는 데 필요한 'service-account.json'은 어디에서 찾을 수 있습니까?
Valentin

2
이는 admin-sdk에 Cloud Storage 추가 항목이 없기 때문입니다. 여기에서 admin-sdk 서비스 계정 json을 얻을 수 있습니다. console.firebase.google.com/project/_/settings/serviceaccounts/…
James Daniels '

18
이 방법으로 생성 된 URL은 엄청나게 깁니다. @martemorfosis 제안 방법으로 생성 된 URL이 훨씬 좋습니다. 해당 URL을 생성하는 기능이 있습니까? 이것이 firebase-sdk를 사용할 때 나중에 사용하기 위해 데이터베이스에 저장하는 것입니다. 미러 메소드는 Functions 도메인에 존재해야합니다.
Bogac

3
배포 된 함수와 함께 service-account.json을 어떻게 업로드 할 수 있습니까? 함수 폴더에 배치하고 package.json의 파일 필드에서 참조하려고 시도했지만 배포되지 않습니다. 감사합니다.
David Aroesti

2
action및 추가해야 expires합니까?
Chad Bingham

82

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

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 덕분에


이미 스토리지에 업로드 된 파일에 대한 유효한 UUID 토큰을 얻으려면 어떻게해야합니까? 무작위 UUID 생성은 도움이되지 않았습니다. 어떤 포인터라도?
DerFaizio

3
@martemorfosis 게시물에서 답변을 찾았습니다. UUID는 object.metadata에서 검색 할 수 있습니다. exports.uploadProfilePic = functions.storage.object (). onChange (event => {const object = event.data; // 스토리지 객체. const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio

버킷 예제 감사합니다! 거의 1 시간 동안 버킷 및 파일 메서드에 대해 다른 조합을 시도했습니다. :)
JCarlosR

1
답변 해 주셔서 감사합니다! 제 경우에는 업로드가 끝났을 때 데이터를 반환하지 않는 bucket.file (fileName) .createWriteStream으로 업로드했기 때문에 encodeURIComponent (file.name) 대신 encodeURIComponent (fileName)을 사용했습니다.
Stanislau Buzunko

2
이것이 정답이되어야합니다. 결과적으로 Firebase SDK (@DevMike)에 의해 생성 된 URL과 유사한 URL이 생성되며, 그 결과 뒤에서 정확히 무엇을하는지 확신합니다.
Samuel E.

64

이 답변은 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을 받고 싶습니다.


10
이에 대한 문제를 만들었 @google-cloud/storage습니다. +1해도됩니다.) github.com/googleapis/nodejs-storage/issues/697
Théo Champion

1
최신 makePublic () 링크.
galki

1
firebaseStorageDownloadTokens더 이상 작동하지 않는 것 같습니다 .
Mason

1
허용되는 답변은 유효하지 않은 만료되지 않는 영구 다운로드 URL을 얻을 수 없음을 나타냅니다. 귀하의 답변에있는 세부 사항은 훌륭하며 정답으로 표시되어야합니다. 감사합니다.
DevMike

2
@thomas 멋진 요약에 감사드립니다! 영구 토큰 다운로드 URL을 얻는 3 가지 방법이 있다고 언급했지만 2 개만 공유했습니다. (a) Firebase 저장소 콘솔에서, (b) getDownloadURL () 프런트 엔드에서. 세 번째 방법은 무엇입니까?
czphilip

23

함수 객체 응답 의 최근 변경으로 다음 과 같이 다운로드 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);

2
의 개체 응답을 참조하고 bucket.file().upload()있습니까? 응답 데이터에서 메타 데이터 속성을받지 못하며 이러한 .NET Framework를 얻는 방법을 모르겠습니다 firebaseStorageDownloadTokens.
Dygerati

또한 [버킷]는있다 bucket.name, 당신은 그것을 하드 코딩이나 여분의 지방 VAR 사용할 필요가 없습니다
칼린 Darie

4
이 솔루션의 문제점은 서비스 URL이 하드 코딩된다는 것입니다. Firebase / Google이 변경하면 중단 될 수 있습니다. metadata.mediaLink속성을 사용 하면 이러한 문제를 방지 할 수 있습니다.
Laurent

2
이와 같은 URL을 구축하는 것은 지원되지 않습니다. 현재는 작동 할 수 있지만 미래에는 중단 될 수 있습니다. 제공된 API를 사용하여 적절한 다운로드 URL을 생성해야합니다.
더그 스티븐슨

1
변경 될 수있는 하드 코딩 된 URL에 의존하는 것은 잘못된 선택입니다.
Laurent

23

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이 필요합니다 . 토큰 생성자 역할을 추가하면이 두 번째 권한 문제가 해결됩니다.


나는 근본적으로 어려운 방법을 마침내 파악한 것과 동일한 세부 사항으로 대답을 남기려고했습니다. 이만큼 일찍 해결책을 읽었 으면 좋겠습니다. / 이것은 12/12/18에서 저에게 효과적이었습니다. 자세한 설명을 해주셔서 감사합니다. 초보자에게 매우 도움이됩니다 !!
Kat

2
내 signedurl이 2 주 후에 만료되지만 키없이 admin.initializeApp ()을 사용하고 있습니다. 이것이 문제입니까? 나는 서비스 에이전트, 난 그냥 지금은 "소유자"를 제거하고 "서비스 계정 토큰 창조주"추가 "소유자"클라우드 기능에 앱 엔진 애플리케이션의 기본 서비스 계정 설정했다
아 미트 브라보

2
서명 된 URL은 7 일 후에 만료됩니다. 만료일을 더 짧게 설정할 수 있지만 더 이상 설정할 수는 없습니다.
Thomas David Kehoe

만료 된 경우 URL을 새로 고치는 방법은 무엇입니까?
Manoj MM

더 긴 시간으로 설정하기 위해 URL을 새로 고치는 방법?
Saifallak 19

17

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


1
uuid 값을 설정하는 예가 있습니까?
Drew Beaupre

1
Drew와 같은 질문을합니다. 메타 데이터를 어디에 설정합니까? bucket.upload 기능을 설정하려고했지만 작동하지 않았습니다.
Vysakh Sreenivasan

1
Vysakh, 나는 예제와 함께 완전한 답변을 게시했습니다. 도움이되기를 바랍니다.
Drew Beaupre는

토큰은 어디서 / 어떻게 생성합니까?
CodyBugstein

3
다운로드 URL은 불투명하고 구성 요소를 분해하거나 조립하지 않아야하므로이 기술은 "안전"하다고 생각하지 않습니다.
더그 스티븐슨

16

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

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


15

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

2
실제로 작동하는 것처럼 보입니다. 지금까지 내가 본 유일한 단점은 브라우저의 URL 표시 줄에서 이미지를 치면 인라인으로 보는 대신 이미지를 다운로드한다는 것입니다.
Michael Giovanni Pumo

file.getMetadata ()는 파일 참조에서 save () 메서드를 사용한 후 나를 위해 트릭을 수행했습니다. firebase-admin sdk와 함께 NodeJS에서 사용합니다.
Pascal Lamers

didnt 한 일, 나는 익명의 발신자가 your_app / image.jpg를에 storage.objects.get 액세스가없는 무엇입니까
마노 MM

9

죄송하지만 위의 질문에 평판이 없어서 댓글을 달 수 없으므로이 답변에 포함하겠습니다.

서명 된 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 
        })

9

나는 제임스 다니엘스가 준 대답에 대해 언급 할 수 없지만 이것은 읽는 것이 매우 중요하다고 생각합니다.

그가 한 것처럼 서명 된 URL을 제공하는 것은 많은 경우에 매우 나쁘고 위험 할 수있는 것처럼 보입니다 . Firebase 문서에 따르면 서명 된 URL은 일정 시간이 지나면 만료되므로이를 databse에 추가하면 특정 시간이 지나면 빈 URL이 생성됩니다.

문서를 오해하고 서명 된 URL이 만료되지 않아 결과적으로 보안 문제가 발생할 수 있습니다. 키는 업로드 된 모든 파일에 대해 동일한 것 같습니다. 즉, 하나의 파일의 URL을 얻으면 누군가 이름 만 알면 액세스 할 수없는 파일에 쉽게 액세스 할 수 있습니다.

내가 그것을 이해하지 못한다면 나는 고쳐야 할 것입니다. 그렇지 않으면 아마도 위에 명명 된 솔루션을 업데이트해야합니다. 내가 틀렸다면


7

이것은 내가 현재 사용하는 것입니다. 간단하고 완벽하게 작동합니다.

Google Cloud로 아무것도 할 필요가 없습니다. Firebase와 함께 즉시 작동합니다 ..

// Save the base64 to storage.
const file = admin.storage().bucket('url found on the storage part of firebase').file(`profile_photos/${uid}`);
await file.save(base64Image, {
    metadata: {
      contentType: 'image/jpeg',
    },
    predefinedAcl: 'publicRead'
});
const metaData = await file.getMetadata()
const url = metaData[0].mediaLink

편집 : 같은 예이지만 업로드 :

await bucket.upload(fromFilePath, {destination: toFilePath});
file = bucket.file(toFilePath);
metaData = await file.getMetadata()
const trimUrl = metaData[0].mediaLink

최신 정보:

메타 데이터를 가져 오기 위해 업로드 메서드에서 두 가지 다른 호출을 할 필요가 없습니다.

let file = await bucket.upload(fromFilePath, {destination: toFilePath});
const trimUrl = file[0].metaData.mediaLink

1
base64로 인코딩되지 않은 파일에 어떻게 사용합니까?
Tibor Udvari

1
그것은하지 mediaLinkenter, 그 단지 미디어 링크
l2aelba


@Sarah 나는 typescript를 사용하여 이것을 작성했지만 모듈 교체가 있는지 확실하지 않습니다.
Oliver Dixon

3

나는 같은 문제가 있었지만 README 대신 firebase 함수 예제 코드를보고있었습니다. 그리고이 스레드에 대한 답변도 도움이되지 않았습니다.

다음을 수행하여 구성 파일 전달을 피할 수 있습니다.

프로젝트의 Cloud Console> IAM 및 관리자> IAM 으로 이동하여 App Engine 기본 서비스 계정을 찾아 해당 구성원에게 서비스 계정 토큰 생성자 역할을 추가합니다. 이렇게하면 앱에서 이미지에 대한 서명 된 공개 URL을 만들 수 있습니다.

출처 : 썸네일 자동 생성 기능 README

App Engine의 역할은 다음과 같습니다.

클라우드 콘솔


3

사전 정의 된 액세스 제어 목록 값 'publicRead'를 사용하면 파일을 업로드하고 매우 간단한 URL 구조로 액세스 할 수 있습니다.

// Upload to GCS
const opts: UploadOptions = {
  gzip: true,
  destination: dest, // 'someFolder/image.jpg'
  predefinedAcl: 'publicRead',
  public: true
};
return bucket.upload(imagePath, opts);

그런 다음 다음과 같이 URL을 구성 할 수 있습니다.

const storageRoot = 'https://storage.googleapis.com/';
const bucketName = 'myapp.appspot.com/'; // CHANGE TO YOUR BUCKET NAME
const downloadUrl = storageRoot + bucketName + encodeURIComponent(dest);

2

이것은 단순한 URL이있는 공개 파일이 필요한 경우에 작동합니다. 이로 인해 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);
    }
});

1

Firebase SDK 및admin.initializeApp :

1- 개인 키 생성 / functions 폴더에 배치합니다.

2-다음과 같이 코드를 구성합니다.

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

선적 서류 비치

try / catch는 다른 파일을 가져오고 각 파일에 하나의 함수를 만드는 index.js를 사용하고 있기 때문입니다. 모든 함수와 함께 단일 index.js 파일을 사용하는 경우 admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.


나를 위해 그것은 '../serviceaccountkey.json'이었지만 ../를 사용하는 머리에 감사드립니다.
로버트 킹

1

firebase 6.0.0부터 다음과 같이 관리자와 직접 저장소에 액세스 할 수있었습니다.

const bucket = admin.storage().bucket();

그래서 서비스 계정을 추가 할 필요가 없었습니다. 그런 다음 위에서 언급 한대로 UUID를 설정하면 firebase URL을 가져 오는 데 효과적입니다.


1

이것이 내가 생각 해낸 최고입니다. 중복되지만 나를 위해 일한 유일한 합리적인 솔루션입니다.

await bucket.upload(localFilePath, {destination: uploadPath, public: true});
const f = await bucket.file(uploadPath)
const meta = await f.getMetadata()
console.log(meta[0].mediaLink)

1

signedURL()사용 하지 않고makePublic()

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp()
var bucket = admin.storage().bucket();

// --- [Above] for admin related operations, [Below] for making a public url from a GCS uploaded object

const { Storage } = require('@google-cloud/storage');
const storage = new Storage();

exports.testDlUrl = functions.storage.object().onFinalize(async (objMetadata) => {
    console.log('bucket, file', objMetadata.bucket + ' ' + objMetadata.name.split('/').pop()); // assuming file is in folder
    return storage.bucket(objMetadata.bucket).file(objMetadata.name).makePublic().then(function (data) {
        return admin.firestore().collection('publicUrl').doc().set({ publicUrl: 'https://storage.googleapis.com/' + objMetadata.bucket + '/' + objMetadata.name }).then(writeResult => {
            return console.log('publicUrl', writeResult);
        });
    });
});


0

오류가 발생하는 경우 :

Google Cloud 함수 : require (…)는 함수가 아닙니다.

이 시도:

const {Storage} = require('@google-cloud/storage');
const storage = new Storage({keyFilename: 'service-account-key.json'});
const bucket = storage.bucket(object.bucket);
const file = bucket.file(filePath);
.....

0

나는 이미 내 ans를 게시했습니다. 아래 URL에 솔루션으로 전체 코드를 얻을 수 있습니다.

Node.js를 사용하여 base64로 인코딩 된 이미지 (문자열)를 Google Cloud Storage 버킷에 직접 업로드하려면 어떻게해야하나요?

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();

    const os = require('os')
    const path = require('path')
    const cors = require('cors')({ origin: true })
    const Busboy = require('busboy')
    const fs = require('fs')
    var admin = require("firebase-admin");


    var serviceAccount = {
        "type": "service_account",
        "project_id": "xxxxxx",
        "private_key_id": "xxxxxx",
        "private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
        "client_email": "xxxx@xxxx.iam.gserviceaccount.com",
        "client_id": "xxxxxxxx",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
      }

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: "xxxxx-xxxx" // use your storage bucket name
    });


    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
    response.set('Access-Control-Allow-Origin', '*');
    const busboy = new Busboy({ headers: req.headers })
    let uploadData = null
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filepath = path.join(os.tmpdir(), filename)
        uploadData = { file: filepath, type: mimetype }
        console.log("-------------->>",filepath)
        file.pipe(fs.createWriteStream(filepath))
      })

      busboy.on('finish', () => {
        const bucket = admin.storage().bucket();
        bucket.upload(uploadData.file, {
            uploadType: 'media',
            metadata: {
              metadata: { firebaseStorageDownloadTokens: uuid,
                contentType: uploadData.type,
              },
            },
          })

          .catch(err => {
            res.status(500).json({
              error: err,
            })
          })
      })
      busboy.end(req.rawBody)
   });




exports.widgets = functions.https.onRequest(app);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.