Google Cloud Function 中的 getSignedURL() 生成的链接可以使用几天,然后返回“SignatureDoesNotMatch”

Posted

技术标签:

【中文标题】Google Cloud Function 中的 getSignedURL() 生成的链接可以使用几天,然后返回“SignatureDoesNotMatch”【英文标题】:getSignedURL() in Google Cloud Function produces link that works for several days, then returns "SignatureDoesNotMatch" 【发布时间】:2019-08-18 15:51:59 【问题描述】:

我的 Firebase Storage getSignedUrl() 下载链接可以工作几天,然后停止工作。错误信息是

SignatureDoesNotMatch
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

去年夏天,GitHub 上有一个很长的 discussion,但我没有看到解决方案。

我正在考虑从前端使用getDownloadURL(),而不是从后端使用getSignedUrl()getDownloadURL() 是否比 getSignedUrl() 更不安全?

这是我的代码,大部分是从documentation复制过来的:

let audioType = 'mp3';
const Storage = require('@google-cloud/storage');
const storage = new Storage();
const bucket = storage.bucket('my-app.appspot.com');
var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + wordFileType);

  // Firebase Storage file options
  var options = 
    metadata: 
      contentType: 'audio/' + audioType,
      metadata: 
        audioType: audioType,
        longAccent: 'United_States',
        shortAccent: 'US',
        longLanguage: 'English',
        shortLanguage: 'en',
        source: 'Oxford Dictionaries',
        word: word
      
    
  ;

  const config = 
    action: 'read',
    expires: '03-17-2025',
    content_type: 'audio/mp3'
  ;

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

【问题讨论】:

您是否尝试过使用显式服务帐户?您链接到的错误将其列为解决方案。 是的,我将 serviceAccount 设置为本地 json 文件,然后 admin.initializeApp 调用 serviceAccount。我调用了 admin.firestore 和 admin.auth,但我从不调用 admin.storage,正如您在上面的代码中看到的那样。相反,我从 Google 文档中处理了“const storage = new Storage();”。也许我应该使用 admin.storage 而不是“new Storage()”?我不清楚“new Storage()”从哪里获得服务帐户。 好的,我已经从“const storage = new Storage();”切换了到“const storage = admin.storage();”。它有效,一个月后问我签名的下载 URL 是否仍然有效!今天早上我重构了我的前端以使用 getDownloadURL() 而不是依靠后端来提供签名的 URL。通过阅读 GitHub 上的讨论,听起来签名 URL 是为了短期使用。 “v4”版本的有效期不能超过一周! Google 每周都会轮换服务密钥。我更喜欢签名 URL,因为 getDownloadURL() 向我的应用程序添加了数百行复杂代码。 【参考方案1】:

Google Cloud Storage 签名网址的最长持续时间为 7 天。但它也可以更短。再也不会了。我猜 Firebase 存储也有同样的限制。

【讨论】:

我犹豫是否给你绿色复选标记,因为这不是我想要的答案,但完全有理由相信你。文档 (cloud.google.com/nodejs/docs/reference/storage/2.3.x/…) 说“过期”是“此链接将过期的时间戳”,而没有说明 7 天的限制。文档示例有“expires: '03-17-2025'”,暗示您可以将到期日期设置为未来几年。但无论我做什么,下载 URL 都会在 7 天后过期。 有什么方法可以从 Google Cloud Function 获取永久下载 URL?我知道如何从浏览器中使用 getDownloadURL(),但我无法让它在云函数中工作。 getDownloadURL() 不是 Node 函数。我可以从浏览器获取永久下载 URL 并从 Cloud Function 获取临时下载 URL,这对我来说似乎很奇怪。不应该反过来吗?浏览器是暂时的,没有人会让他们的浏览器保持打开一周。但是当我从云函数上传文件时,它是永久的,下载 URL 应该是永久的, 如果您对 Cloud Storage 中的对象启用公共访问权限,则可以使用指向该对象的直接 URL。每个拥有该 URL 的人都可以下载该对象。 @ThomasDavidKehoe 确实如此,请查看此链接:cloud.google.com/storage/docs/access-control/… 然后搜索“7 天”。你会看到限制【参考方案2】:

我已经为这个问题写了一个很长的答案:[Get Download URL from file uploaded with Cloud Functions for Firebase。此问题可以标记为重复。



  [1]: https://***.com/questions/42956250/get-download-url-from-file-uploaded-with-cloud-functions-for-firebase

【讨论】:

十天后,签名的下载 URL 已失效。问题未解决! Thomas David Kehoe - 你有没有找到解决这个问题的方法?这个问题让我发疯了很长时间。 @barrylachapelle,我在这里写了一个很长的答案:***.com/questions/42956250/… 我正在测试另一个人建议的想法(使用 uuidv2 而不是 uuidv4),一周后问我这是否有效!【参考方案3】:

预签名 URL 将在您使用 expires 字段提供的日期到期。

但是,您在此处看到的问题是管理 SDK 的 KMS 密钥每 7 天轮换一次。因此,如果您使用自动配置的 storage() 库创建预签名 URL,一旦密钥轮换,您的预签名 URL 将不再有效(因为用于签名的密钥不再有效)。因此,您的 URL 的有效期将少于或等于 7 天,具体取决于密钥的使用时间。

相反,您无需使用管理 SDK,而是使用 Google Cloud Storage npm module 并使用服务帐户 json 对其进行初始化。

const storage = new Storage(keyFilename: "key.json");

`const storage = new Storage(credential: require("key.json"));

【讨论】:

以上是关于Google Cloud Function 中的 getSignedURL() 生成的链接可以使用几天,然后返回“SignatureDoesNotMatch”的主要内容,如果未能解决你的问题,请参考以下文章

无法在安全的Google Cloud Function上获得CORS错误

Google Cloud Function - ImportError:无法从“google.cloud”(未知位置)导入名称“pubsub”

从 Google Cloud Function (Python) 将新文件写入 Google Cloud Storage 存储桶

如何从Google Cloud Function(Cheerio,Node.js)发出多个http请求

从 Cloud Function (python) 写入 Google Cloud Storage

Cloud Function 部署问题以安排每日 Cloud SQL 导出到 Google Cloud Storage