通过 Firebase 身份验证和存储设置文件上传限制,中间没有服务器?
Posted
技术标签:
【中文标题】通过 Firebase 身份验证和存储设置文件上传限制,中间没有服务器?【英文标题】:Setting limits on file uploads via Firebase auth and storage without server in the middle? 【发布时间】:2017-03-23 15:00:23 【问题描述】:我正在学习有关 Firebase 身份验证和网络应用中的存储的知识。我的想法是要求用户通过 Firebase 登录,然后上传图片。
我可以看到这可以通过 Firebase 身份验证和存储来实现。但是,我想限制他们可以上传的文件数和文件大小。
是否可以在 Firebase 控制台(或其他地方)内控制上传?在查看了 javascript 示例之后,我了解了如何将文件放入其中,并且我可以想象编写代码来查询 Firebase 以获取用户的上传计数,然后在客户端进行限制,但当然,这是一种完全不安全的方法。
如果我将它作为单页应用程序托管在 GitHub 页面上,我想知道是否可以在不涉及服务器的情况下设置这些限制。或者,我是否需要通过服务器代理我的上传,以确保我绝不允许用户上传超出我预期的内容?
【问题讨论】:
我看到很多教程和答案都描述了完全不安全的方法,作者甚至断言它是安全的:( 【参考方案1】:您可以限制用户可以通过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");
【讨论】:
这个文件名破解是我见过的最好的。您可以改为使用 Cloud Functions 调整文件大小,以便在事后稍微捕获规则破坏者,但这更加复杂和脆弱。 使用云函数、firestore 和 auth 声明,可以做到。请参阅下面的答案。【参考方案2】:如果您需要每个用户的存储验证,则该解决方案有点棘手,但可以做到。
Ps.:您需要使用 Cloud Functions 生成 Firebase 令牌,但服务器不会在中间进行上传...
https://medium.com/@felipepastoree/per-user-storage-limit-validation-with-firebase-19ab3341492d
【讨论】:
【参考方案3】:一种解决方案可能是使用 Admin SDK 根据保存每天上传计数的 Firestore 文档更改存储规则。
假设您有一个 userUploads/uid
的 Firestore 集合/文档,其中包含字段 uploadedFiles: 0
和 lastUploadedOn
。
现在,一旦用户将文件上传到 Firebase 存储(假设在限制范围内且没有错误),您就可以触发 Cloud Function,它将读取 userUploads/uid
文档并检查 lastUploadedOn
字段是否早于当前日期上传文件的日期,如果是,则将 uploadedFiles
设置为 1 并将 lastUploadedOn
更改为上传的日期时间。否则,增加uploadedFiles
计数并将lastUpdateOn
更改为当前日期时间。一旦 uploadedFiles
值变为 10(您的限制),您可以使用 Admin SDK 更改存储规则。请参阅示例here。然后,将 userUploads/uid
文档中的计数更改为 0。
但是,有一点需要注意。规则的更改可能需要一些时间,并且该规则不应正在处理合法的异步工作。来自Admin SDK:
Firebase 安全规则需要 几分钟才能完全部署。使用 Admin SDK 部署规则时,请确保避免竞争条件,在这种情况下,您的应用会立即依赖尚未完成部署的规则
我自己没有尝试过,但看起来它会起作用。再想一想,更改规则以允许写入可能会很复杂。如果用户在第二天上传(规则更改后),上传错误处理程序可以触发另一个云函数来检查它是否是合法请求,将规则更改为正常并在一段时间后再次尝试上传,但它会是非常糟糕的用户体验。另一方面,如果您使用调度程序云功能每天检查 userUploads/uid
文档并重置值,则成本可能会很高(每百万用户每月约 18 美元 @ 0.06 美元/10 万次读取),并且如果用户在不同的时区,对于大多数用户来说可能无关紧要,这取决于他们是否经常上传。此外,规则有限制
因此,针对大型用户群的每个用户规则可以轻松达到此限制(除了其他规则)。
也许最佳解决方案可能是使用Auth Claims
。如果用户具有特定的身份验证声明令牌(例如canUpload: false
),则最初具有拒绝写入规则。然后在上传时触发的云功能中,当用户达到限制时附加此声明。这将是实时的,因为它会立即阻止用户,以防止 Admin SDK 规则部署延迟。
要删除身份验证声明:
-
通过上传错误处理程序中的另一个云函数检查
lastUploadedOn
是否已更改,从而删除声明
通过在上传前调用的单独云函数检查用户是否有 auth 声明并且 lastUploadedOn
是更早的日期,然后删除声明
此外,在登录过程中,如果lastUploadedOn
早于今天,则可以检查并删除它,但它的效率低于 2,因为它会在用户甚至没有上传任何内容时在 firestore 上构成不必要和不必要的读取
在 2 中,如果客户端尝试跳过呼叫,并且拥有身份验证声明,则她/他将无法上传,因为安全规则已阻止。否则,如果没有 auth 声明,那么他/她将通过正常流程。
注意:更改身份验证声明需要推送到客户端。看到这个doc。
【讨论】:
以上是关于通过 Firebase 身份验证和存储设置文件上传限制,中间没有服务器?的主要内容,如果未能解决你的问题,请参考以下文章
从 firebase 下载文件并上传到 Stripe 进行身份验证
如何在不使用 Firebase 身份验证的情况下保护 Firebase 存储? (下一个)