Firebase云存储规则能否针对Firestore数据进行验证?

41

我们能否使用Firestore数据来授予或限制访问在Firebase Cloud Storage上托管的文件?

我想要用作Firebase安全规则的示例

allow write: if get(/databases/mydbname/documents/guilds/$(guildID)).data.users[(request.auth.uid)] in ["Admin", "Member"];
3个回答

41

更新(2022年10月):现在可以使用新的firestore.get()firestore.exists()函数从 Cloud Storage 安全规则内访问 Cloud Firestore 了。请参阅博客文章“Announcing cross-service Security Rules”“使用 Cloud Firestore 增强 Cloud Storage 安全规则”的文档

以下是以前的答案,供参考:

目前没有办法从另一个产品的安全规则内访问不同的 Firebase 产品。请参见:is there a way to authenticate user role in firebase storage rules?

但似乎你正在尝试检查用户的组成员身份。我建议你将其建模为所谓的自定义声明。而不是在数据库中查找组成员资格,您可以通过使用 Firebase Admin SDK 将声明“用户 {uid} 是 {guild1} 组的成员”写入用户配置文件中(或者除此之外):“通过管理 SDK 设置和验证自定义用户声明”

admin.auth().setCustomUserClaims(uid, {guild1: true}).then(() => {
  // The new custom claims will propagate to the user's ID token the
  // next time a new one is issued.
});

完成这一步后,您可以在安全规则中检查公会成员身份:

allow read: if request.auth.token.guild1 == true;

我不确定如何将公会成员资格建模为地图,如果这种情况发生,我会更新这个答案。


1
将基于云Firestore触发器从数据库中填充自定义声明,看看是否可行。 - Remi
6
截至2021年,这是否仍然是事实? - Andrew
2
无论是无法从安全规则内访问其他产品,还是解决方法,两者仍然有效。 - Frank van Puffelen
您还可以使用云存储触发器,如果上传未通过 Firebase 验证,则最终会将其删除。 - Jonathan
是的,@Jonathan,这总是一个选项。如果您能更详细地说明如何做到这一点,那可能会成为一个很好的备选答案。 - Frank van Puffelen

8
Firebase最近宣布了跨服务安全规则,使您可以在Firebase存储的安全规则中访问Firestore数据。您只需要在get()exist()函数之前使用firestore.前缀,如下所示:
allow write: if firestore.get(/databases/(default)/documents/col/docId/).data.field == "value";

Firebase目前每个项目只支持一个数据库实例,因此名称必须在路径中为(default)。这不是Firestore规则中的通配符,因此不是$(database)

2
更新:截止到2022年9月28日,Firebase引入了跨服务安全规则(cross-service Security Rules),因此下面的答案已经过时。请参见@Dharmaraj的答案以获取示例。
您可以使用云函数触发器在上传文件后进行追溯验证和删除文件。
警告:这种技术并非百分之百可靠,如果云函数触发器失败,则无效文件将被暂时或可能永久存储在云存储中。我更喜欢预防上传,但是如果用于决定权限的逻辑驻留在Firestore中且无法放置在自定义声明中,则这是当前使用Firebase的客户端SDK上传文件的唯一方式。如果您正在构建重要任务系统,则应将文件上传到Cloud Function,并让Cloud Function将文件存储在Cloud Storage中。
上传文件时,请添加一些元数据表示谁在上传:
      const storageRef = ref(
        storage,
        `files/${fileName}`,
      );
      const uploadTask = uploadBytesResumable(storageRef, file, {
        customMetadata: {
          uploaderId: userId,
        },
      });

设置存储规则以确保用户身份元数据可信:
    match /files/{fileName} {
      allow create: if request.auth != null &&
        request.resource.metadata.uploaderId == request.auth.uid
    }

创建一个云函数触发器,可以回溯地验证和删除:
export const onFinalize = functions
  .storage.object()
  .onFinalize(async object => {

    // We can trust object.metadata.uploaderId, so check Firestore if user is able to upload file
    if (!(await canUploadFile(object.metadata.uploaderId, object.name))) {
      await storage.bucket(object.bucket).file(object.name).delete();
      throw new Error(
        `Permission error: ${object.metadata.uploaderId} not allowed to upload ${object.name}`,
      );
    }

    // Continue
  });

1
你的答案是最好的,谢谢 :))) - Arthur Arakelyan
请查看@Dharmaraj的答案,因为他的技术是执行此操作的新推荐方式。 - Johnny Oshika

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接