【问题标题】:Access Firebase Cloud Storage server-side with security rules applied访问已应用安全规则的 Firebase Cloud Storage 服务器端
【发布时间】:2021-04-10 03:18:22
【问题描述】:

在我的 Firebase 应用中,我想知道代表已登录用户(通过 ID 令牌进行身份验证)向 Cloud Storage for Firebase 发出服务器端请求的推荐方式,并将安全规则应用于请求(即不使用 Admin SDK)。

目前整个应用流程如下所示:

  • 用户登录客户端并向 Google Cloud API 网关发出请求,并在请求标头中发送其ID token
  • API 网关 authenticates user 并将请求转发到后端 API 中的不同端点:
    • 如果是Firebase身份验证的请求,API使用Auth Admin SDK直接处理
    • 如果是Firestore,API使用API​​网关转发的x-forwarded-authorization请求头(包含客户端最初提供的ID令牌)向Firestore's REST API发出请求,以便可以通过安全规则评估请求。

对于 Cloud Storage,我想做类似于上述 Firestore 案例的操作,但文档中没有特定于 Firebase 的 REST API。可以只让客户端直接向 Firebase 发出请求(如 answer 中所建议的那样),但更愿意将逻辑保留在后端。

对于存储是否有替代方法?请随时指出是否有更好的方法来处理上述 Firebase Auth 和 Firestore 案例。谢谢!

编辑:在我找到它们时添加更多可能的解决方案

  • Doug 的回答 here 和 Frank 的回答 here 建议使用 Cloud Storage REST API,应用程序会在该 API 中为用户和 makes the request 生成 OAuth 令牌
  • 这个答案here 提到可以将auth=IDTOKEN 查询参数传递给Firebase REST API:

获得 ID 令牌后,您可以通过 auth 查询参数来验证请求。请求尊重 Firebase 安全规则,就像登录客户端的最终用户是 提出请求。

【问题讨论】:

  • 您好,弗兰克,抱歉耽搁了。现在会回复他们!

标签: node.js firebase google-cloud-firestore firebase-authentication


【解决方案1】:

在考虑了上述各种选项之后(感谢 Frank 和 som!),就我而言,最好的选择是改变现状并直接从客户端发出存储请求。两个主要原因是:

  • 这是最简单的实现,因为已经有一个 SDK 允许您执行此操作
  • 与 Firebase 存储交互可能涉及大型对象,因此如果网络行程过多,用户体验可能会受到影响

从客户端发出请求时,如果出现 XMLHttpRequest is not defined 错误,上面 som 的回答和 this answer 可能会派上用场

【讨论】:

    【解决方案2】:

    2020 年 1 月 6 日编辑:此方法已在高负载下进行了几天的测试。有关一些小的新要求,请参见底部。

    原始回复:这不是答案,而是生态系统内的解决方法(对我有用!)

    基本上,关于离线优先/可能不安全的物联网设备,我有一个类似的用例,需要使用安全规则进行基于身份验证的存储访问。今天早上,我查看了Firebase js sdk repo,并注意到原生 XHR API 是工作节点实现中缺少的主要部分。

    我在this github issue 上详细说明了我的解决方法......为方便起见,此处包括:

    .. 使用 XHR polyfill 修补存储库实际上似乎有效(节点 15 / 到目前为止的最小测试)。具体来说,我已经安装了xmlhttprequest-ssl 并将其导入到存储模块的顶部(在我的情况下,@firebase/storage/dist/index.cjs.js 中的第 5 行):

    var XMLHttpRequest = require("xmlhttprequest-ssl").XMLHttpRequest;
    

    回到应用程序中,我照常导入firebase/storage,然后从本地文件系统加载文件并按照标准 Firebase API 上传:

    import { firebase } from "@firebase/app";
    import "@firebase/storage";
    
    /* include Firebase setup, etc. */
    
    const filename = 'offline-user-generated-image.jpg';
    const file = fs.readFileSync(filename); // for brevity only
    const ref = firebase.storage().ref().child(`test/${filename}`);
    
    // use the buffer's underlying arraybuffer 
    ref.put(file.buffer, {
      contentType: 'image/jpg', // defaults to 'application/octet-stream'
      customMetadata: {
        uid: 'abc123', // for enhanced security rules
      },
    })
    .then(() => console.log('done'))
    .catch(e => console.log(e));
    

    存储规则适用于上传(哇!),安全令牌和自定义元数据按预期应用。还使用“putString”进行了测试。这为我的用例解决了一些相当激烈的解决方法,因为这意味着我可以保留我的逻辑/身份验证/等。完全在 Firebase 生态系统中。热衷于倾听他人的想法。

    注意:我使用patch-package 来确保补丁在安装/升级过程中保持不变。

    2020 年 1 月 6 日更新:一些额外的点点滴滴

    事实证明,存储包中有一个未清除的超时,这会导致节点进程陷入困境(并且可能在所有环境中都是资源占用).. 我有 submitted a PR(几乎是 clearTimeout)那解决了这个问题,但与此同时,这也需要手动修补,除非您可以在代码中安全地process.exit(0)

    【讨论】:

    • 我相信您指的是客户端 SDK 是吗?我没有在我的服务器中使用它,所以我以前不能用它来验证请求是否符合安全规则。但是当试图从客户那里做这件事时,你的回答很有帮助,还有这个:stackoverflow.com/questions/55671126/…
    • 是的,很抱歉在这里有点不清楚。正如@FrankvanPuffelen 所提到的,客户端 SDK 是您可以达到存储规则的唯一方法。上面的补丁允许您在节点中使用客户端存储 api,这应该可以解决您的问题。我以前在节点中并排运行了管理员和客户端 sdks,没有问题(代表用户点击 rtdb 规则)。在我目前的情况下,我在一个不安全的节点服务器上(因此无法存储管理员凭据)并且正在使用上面的补丁来单独使用客户端 sdk 提供存储访问权限。
    【解决方案3】:

    在使用 Admin SDK 时,无法强制执行 Firebase 的 Cloud Storage 安全规则。 Firebase 没有为 Cloud Storage 提供文档化的 REST API,我怀疑 Google Cloud REST API for Storage 是否接受 Firebase ID 令牌。

    所以我真的认为您没有很好的选择可以代表您的用户从服务器执行此操作。我能想到的两个选项:

    1. 将必要的信息传回给客户端,并让客户端通过 Firebase SDK 访问数据 - 在这种情况下,安全规则会被强制执行。
    2. 在您的 Cloud Functions 代码中复制必要的安全逻辑。

    【讨论】:

    • 感谢弗兰克的信息。您说得对,Google Cloud REST API 不接受 Firebase ID 令牌。我最终所做的是重新安排事情并直接从客户端进行(而不是从服务器传递)。将在下面添加一个答案来详细说明。
    猜你喜欢
    • 2018-11-27
    • 2021-07-05
    • 2017-12-06
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 2019-08-28
    • 2021-07-29
    • 2018-12-15
    相关资源
    最近更新 更多