Firebase Firestore规则和查询文档地图,使用电子邮件密钥与用户共享数据

Firebase Firestore规则和查询文档地图,使用电子邮件密钥与用户共享数据,firebase,google-cloud-firestore,firebase-security,Firebase,Google Cloud Firestore,Firebase Security,用例摘要 firebase.firestore().collection('stories').where(`roles.${user.uid}.hasRole`, '==', true) firebase.firestore().collection('stories').where(`roles.${user.email}.hasRole`, '==', true) 用户A创建一个故事 用户A通过电子邮件(通过云功能发送)与未知(应用程序)用户B分享故事 用户B收到一封关于故事的电子邮件

用例摘要

firebase.firestore().collection('stories').where(`roles.${user.uid}.hasRole`, '==', true)
firebase.firestore().collection('stories').where(`roles.${user.email}.hasRole`, '==', true)
  • 用户A创建一个故事
  • 用户A通过电子邮件(通过云功能发送)与未知(应用程序)用户B分享故事
  • 用户B收到一封关于故事的电子邮件
  • 用户B访问应用程序并创建新帐户
  • 用户B查看/读取用户A创建的故事
  • 注意:只有与之共享或创建故事的人才能看到故事

    我正在建立一个基于角色的访问系统。我一直在看这张照片,我少了一张

    考虑一个故事,该故事只能由共享该故事的用户阅读。包括firestore示例在内的大多数示例都使用
    UID
    来识别共享用户。但是,该用户当前可能不是firebase应用程序的用户。此外,用户如何分配该UID

    故事数据

    {
      title: "A Great Story",
      roles: {
        aliceUID: {
          hasRole: true,
          type: "owner",
        },
        bobUID: {
          hasRole: true,
          type: "reader",
        }
      }
    }
    
    {
      title: "A Great Story",
      roles: {
        alice@yahoo.com: {
          hasRole: true,
          type: "owner",
        },
        bob@gmail.com: {
          hasRole: true,
          type: "reader",
        }
      }
    }
    
    故事查询

    firebase.firestore().collection('stories').where(`roles.${user.uid}.hasRole`, '==', true)
    
    firebase.firestore().collection('stories').where(`roles.${user.email}.hasRole`, '==', true)
    
    第二部分可能通过维护一个单独的用户集合来解决,然后您可以从他们的电子邮件地址中找到该用户,但这不包括从未登录的用户

    打算分享故事的用户可以添加具有电子邮件地址的用户。然后使用firebase功能,我们可以发送电子邮件通知用户共享的故事,用户可以登录应用程序并阅读该故事

    如果我们继续使用此方法,那么您将没有UID,而只有电子邮件地址作为密钥

    故事数据

    {
      title: "A Great Story",
      roles: {
        aliceUID: {
          hasRole: true,
          type: "owner",
        },
        bobUID: {
          hasRole: true,
          type: "reader",
        }
      }
    }
    
    {
      title: "A Great Story",
      roles: {
        alice@yahoo.com: {
          hasRole: true,
          type: "owner",
        },
        bob@gmail.com: {
          hasRole: true,
          type: "reader",
        }
      }
    }
    
    故事查询

    firebase.firestore().collection('stories').where(`roles.${user.uid}.hasRole`, '==', true)
    
    firebase.firestore().collection('stories').where(`roles.${user.email}.hasRole`, '==', true)
    
    更新了Firestore规则-来自

    我无法使电子邮件查询正常工作。这提到

    不幸的是,点不允许作为贴图键。所以电子邮件地址不起作用

    我不明白为什么这会是规则方面的冲突。它确实构成了一个可能无效的where子句

    e、 g

    这看起来像是无效的JS,不幸的是
    [
    ]
    是无效字符,所以我们不能这样做

    .where(`roles[${user.email}]hasRole`, '==', true)
    
    我看到的最后一件事是使用类似于

    function encodeAsFirebaseKey(string) {
      return string.replace(/\%/g, '%25')
        .replace(/\./g, '%2E')
        .replace(/\#/g, '%23')
        .replace(/\$/g, '%24')
        .replace(/\//g, '%2F')
        .replace(/\[/g, '%5B')
        .replace(/\]/g, '%5D');
    };
    
    这似乎修复了查询
    where
    子句,它是一个有效的数据结构,但这并不意味着它没有真正的安全强制

    关于如何实现这一点有什么想法吗?请包括有效的数据结构、firestore规则和查询。我已经展示并看到了很多例子,它们三分之二都是无效的解决方案


    谢谢

    从我收集的信息来看,你想让一个故事成为私人故事,但可以与任何人分享。你最担心的是那些没有应用但有共享链接的用户

    因此,您最大的问题是firebase的工作方式意味着您无法在不使用某种登录的情况下限制对数据的访问

    如果您同意要求新用户登录,那么您的答案应该是动态链接。这些链接在安装和登录过程中始终保持不变,这意味着任何人都可以获得一个动态链接,该链接附带故事访问数据。您只需在应用程序的
    main活动
    AppDelegate
    等效项中添加一个侦听器,即可记录动态链接数据并在登录后运行特定任务

    如果您希望完全远离登录,那么您可以设置动态链接以绕过登录过程,并将新安装用户直接指向故事。但是,第二个选项需要更多的工作,而且安全性较低,因为您可能会被迫复制故事数据,以便对任何具有适当故事链接的人进行开放访问。

    这是一个使用案例

    Firebase Admin SDK支持在用户上定义自定义属性 账户。这提供了实现各种访问的能力 Firebase中的控制策略,包括基于角色的访问控制 应用程序。这些自定义属性可以为用户提供不同级别的 访问(角色),在应用程序的安全规则中强制执行

    可以为以下常见情况定义用户角色:

    • 授予用户访问数据和资源的管理权限
    • 定义用户所属的不同组
    • 提供多级访问:
    • 区分付费/未付费订户
    • 区分版主和普通用户
    • 教师/学生申请表等
    您需要建立一个节点服务器(技能级别较低)。下面这样的脚本用于生成声明

    var admin = require('firebase-admin');
    
    var serviceAccount = require("./blah-blah-blah.json");
    
    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        databaseURL: "https://my-app.firebaseio.com"
    });
    
    admin.auth().setCustomUserClaims("9mB3asdfrw34ersdgtCk1", {admin: true}).then(() => {
        console.log("Custom Claim Added to UID. You can stop this app now.");
    });
    
    然后在客户端,执行以下操作:

    firebase.auth().onAuthStateChanged(函数(用户){ 如果(用户){


    });

    基本的问题是,我不知道如何正确地表达一个有效的查询。事实证明,您不需要在一行中创建一个查询

    可以使用构造查询参数

    var path = new firebase.firestore.FieldPath('roles', email ,'hasRole');
    firebase.firestore().collection('stories').where(path, '==', true)
    

    这解决了原始缺失的部分。

    我没有使用过它,但您可能能够实现我在firebase匿名登录功能中提到的“无登录”效果,但我从未使用过它,因此这只是一个建议,以了解这是否是您需要的,并且您希望保持数据库安全,动态链接看起来非常有希望这是我最初的想法。但是,我正在创建一个web应用程序,因此我相信这将只产生一个常规链接。文档中没有提到接收web的动态链接。可能因为它只是一个url?考虑到这一点,我需要用一些标识符更新故事角色图,我已经在使用电子邮件,一旦用户登录,我就可以使用电子邮件将需要使用UID更新电子邮件密钥。我认为这是可行的,但云功能不会在保证的时间内执行,因此用户最初可能看不到故事。感谢您提供的信息,我认为这一定是我唯一没有彻底阅读的文档部分。这些文档都引用了实时数据库和