在中间没有服务器的情况下通过 Firebase 身份验证和存储设置文件上传限制?

Setting limits on file uploads via Firebase auth and storage without server in the middle?

我正在学习网络应用程序中的 Firebase 身份验证和存储。我的想法是让用户通过 Firebase 登录,然后上传一张图片。

我可以从 Firebase 身份验证和存储中看出这是可能的。但是,我想限制他们可以上传的文件数量和文件大小。

是否可以在 Firebase 控制台(或其他地方)控制上传?查看 JavaScript 示例后,我了解了如何放入文件,我可以想象编写代码查询 Firebase 以获取用户的上传计数,然后在客户端进行限制,当然,这是一个完全不安全的方法。

如果我将其作为单页应用托管在 GitHub 页面上,我想知道是否可以在不涉及服务器的情况下设置这些限制。或者,我是否需要通过服务器代理我的上传,以确保我绝不允许用户上传超出我预期的内容?

您可以限制用户可以通过 Firebase Storage's security rules 上传的内容。

例如,这(来自链接文档)是一种限制上传文件大小的方法:

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

但是目前这些规则中没有办法限制用户可以上传的文件数量。

想到的一种方法是为此使用固定的文件名。例如,如果您将允许的文件名限制为编号 1..5,则用户只能存储五个文件:

match /public/{userId}/{imageId} {
  allow write: if imageId.matches("[1-5]\.txt");
}

如果您需要对每个用户进行存储验证,该解决方案会有点棘手,但可以完成。

Ps.: 您将需要使用 Cloud Functions 生成一个 Firebase 令牌,但服务器不会在中间进行上传...

https://medium.com/@felipepastoree/per-user-storage-limit-validation-with-firebase-19ab3341492d

一种解决方案可能是使用 Admin SDK 根据保存每天上传计数的 Firestore 文档更改存储规则。

假设您有一个 firestore collection/document 作为 userUploads/uid 具有字段 uploadedFiles: 0lastUploadedOn.

现在,一旦用户将文件上传到 Firebase 存储(假设在限制范围内且没有错误),您可以触发 Cloud Function,它将读取 userUploads/uid 文档并检查 lastUploadedOn 字段是比当前上传文件的日期更早的日期,如果是,则将 uploadedFiles 设为 1 并将 lastUploadedOn 更改为上传日期时间。否则,增加 uploadedFiles 计数并将 lastUpdateOn 更改为当前日期时间。一旦 uploadedFiles 值变为 10(您的限制),您可以使用 Admin SDK 更改存储规则。请参阅示例 here。然后,在 userUploads/uid 文档中将计数更改为 0。

但是,有一点需要注意。规则的更改可能需要一些时间,并且该规则的进程中不应有合法的异步工作。来自 Admin SDK:

Firebase security rules take a period of several minutes to fully deploy. When using the Admin SDK to deploy rules, make sure to avoid race conditions in which your app immediately relies on rules whose deployment is not yet complete

我自己还没有尝试过,但看起来它会起作用。转念一想,改回允许写入的规则可能很复杂。如果用户在第二天上传(规则更改后),上传错误处理程序可以触发另一个云功能来检查它是否是合法请求,将规则更改回正常并在一段时间后再次尝试上传,但它会会很糟糕的用户体验。另一方面,如果您使用调度程序云功能每天检查 userUploads/uid 文档并重置值,则成本可能很高(每月每百万用户约 18 美元 @ 0.06 美元/10 万次读取)并且如果用户处于不同的时区,对于大多数用户而言可能无关紧要,这取决于他们是否经常上传。此外,规则有限制

  • 序列化时,规则必须小于 64 KiB 的 UTF-8 编码文本
  • 一个项目总共最多可以部署 2500 个规则集。一旦达到此限制,您必须在创建新规则集之前删除一些旧规则集。

因此,针对大型用户群的每个用户规则很容易达到此限制(除其他规则外)。

也许 最佳解决方案 可以是使用 Auth Claims。如果用户具有特定的身份验证声明令牌(例如 canUpload: false),则最初具有拒绝写入规则。然后在上传时触发的云功能中,在用户达到限制时附加此声明。这将是实时的,因为它会立即阻止用户反对 Admin SDK 规则部署延迟。

删除授权声明:

  1. 如果 lastUploadedOn 已更改,请检查上传错误处理程序中的另一个云功能,从而删除声明
  2. 通过上传前调用的单独云功能进行检查,检查用户是否有授权声明并且 lastUploadedOn 是更早的日期,然后删除声明
  3. 此外,在登录期间,如果 lastUploadedOn 早于今天,则可以检查并删除它,但它的效率低于 2,因为它会在用户甚至没有上传时构成对 firestore 的不必要和不必要的读取任何东西

在 2 中,如果客户端尝试跳过调用,并且有 auth 声明,s/he 永远无法上传,因为被安全规则阻止。否则,如果没有授权声明,那么 s/he 将通过正常流程。

注意:更改授权声明需要推送到客户端。看到这个 doc.