【问题标题】:Firebase rules variable not matching as stringFirebase 规则变量与字符串不匹配
【发布时间】:2020-12-07 00:34:21
【问题描述】:

所以我试图在我的 Firestore 规则中将用户电子邮件与集合名称匹配,如下所示:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {  
    match /users/{userEmail} {
      allow read: if request.auth.token.email.matches(userEmail);      
    }
  }
}

我知道将集合 ID 设置为电子邮件不是一个好习惯,但请假设它是 any 字符串。 上述方法不起作用。但是,如果我将 request.auth.token.email.matches(userEmail) 替换为 request.auth.token.email.matches("myemail@gmail.com"),它就可以正常工作。

上面我的用户集合中有一个 id = myemail@gmail.com 的文档,那么为什么当我使用 userEmail 变量时它不匹配,但如果我使用“myemail@gmail.com”字符串会匹配?

附加信息: 请求/getAccountInfo你可以看到myemail@gmail.com作为电子邮件

应用代码

我使用 Vuexfire 进行火库绑定。 store/index.js

bindUsers: firestoreAction(({bindFirestoreRef}) => {  
    return bindFirestoreRef("users", db.collection("users")
    .where('email', '==', 'myemail@gmail.com');
}),

App.vue

async mounted() {
    if (firebase.auth.currentUser) {
        // Bind Vuexfire after if/when user exists to capture Firestore changes
        await this.$store.dispatch("bindUsers");
    }
}

【问题讨论】:

  • 安全规则本身不做任何事情。它们仅在与来自网络或移动应用程序的特定查询配对时才有意义。请编辑您的问题以显示该代码,并证明(可能通过登录)用户在查询时使用正确的电子邮件地址登录。
  • @DougStevenson 我已经更新了我上面的截图。如果request.auth.token.email.matches("myemail@gmail.com") 有效,那么在我的应用程序加载时不会确认我有用户身份验证吗?只有当我替换为userEmail 时,我才会得到FirebaseError: Missing or insufficient permissions.,并且您可以从我的屏幕截图中看到文档名称为myemail@gmail.com ... 难道它不像@ 可能吗?
  • 我们需要执行查询的客户端应用程序代码,正如我在第一条评论中所述。截图并不能说明全部。
  • 我正在使用 Vuexfire 绑定到我的集合,here。我只有在安装我的应用程序和if (firebase.auth.currentUser) 后才开始绑定。如果我更新规则以使用“myemail@gmail.com”字符串而不是 {user} 变量,我仍然很困惑为什么它会起作用?
  • 我认为您不能直接从“match /users/{userEmail}”行中使用“userEmail”变量(不是 100% 肯定,但这可能就是您当前 userEmail 值的原因无效。

标签: firebase google-cloud-firestore firebase-security


【解决方案1】:

您的查询正在过滤名为电子邮件的文档属性(不是其 ID):

return bindFirestoreRef("users", db.collection("users")
.where('email', '==', 'myemail@gmail.com');

这与用户 Firebase 身份验证帐户中的电子邮件令牌无关。您根本没有证明您在文档中有 email 属性 - 您所拥有的只是一个 文档,其 ID 包含电子邮件地址。

您的查询最终需要匹配限制查询的规则。这意味着您需要某种方式在客户端上以匹配规则约束的方式显式过滤。这意味着您将不得不对具有 ID 的特定文档使用 get() 类型查询,而不是需要使用 where 子句进行过滤的集合查询。

【讨论】:

  • 首先,感谢您的帮助和耐心 :) 其次...我认为这是我所缺少的魔法部分,但让我确认我理解正确。为了使用 .where() 过滤集合中的文档,您需要访问所有文档,以便 .where() 可以“查看每个文档”?
  • 在所有情况下,您的查询过滤器都必须符合规则的约束条件。规则不会为您过滤结果。这在documentation 中有介绍。如果您的查询可能匹配任何规则不允许的文档,那么整个查询将失败。由于您的规则只允许用户访问与其电子邮件地址匹配的一个文档,因此您的查询应该只尝试获取该一个文档,仅此而已。
  • 因为我的收藏中有一个文档,所以我可以将我的 .where() 全部排除在外(并且理解的规则不是过滤器)。在我的收藏中使用我的 ONE 文档,这条规则有效:if request.auth.token.email.matches("myemail@gmail.com"); 而这个不适用 request.auth.token.email.matches(userEmail);
  • 集合中有多少文档并不重要。规则仍然不会接受需要过滤器的查询。它不会检查每一个 - 这不会扩展,而且本质上是过滤器必须做的事情。
【解决方案2】:

我可能是错的,但看起来您编写的规则更像是过滤器而不是安全规则。

@DougStevenson 会比我清楚得多,但是如果您对字符串值进行硬编码,那么 Firestore 可以明确确定该规则是成功还是失败。但是,如果您使用变量,那么我相信 Firestore 通常会确定规则是返回 true 还是 false - 而不是特定的运行时情况。在这种情况下,规则应返回 false,因为会有未通过测试的行。

看起来您正在尝试使用您的规则来过滤掉行。 Firestore 规则不能那样工作。

正如 Doug 所建议的,您应该向我们展示一些您用于访问该集合的客户端代码,以便我们确定该代码是否落入“规则试图成为过滤器”的陷阱。

【讨论】:

  • 我已经更新了我的原始评论,说明我是如何绑定到 Firestore 的。我了解 Firestore 规则不应用过滤,但我尝试将其作为我查询的一部分,以便过滤后的查询将匹配该用户的规则。但是,我在评论中的测试用例是一个单一的文档(所以它是全有或全无)。如果我硬编码文档 ID:“myemail@gmail.com”,我的规则可以正常工作,但如果我使用 documentId 变量:“{userEmail}”(只有users是 myemail@gmail.com)。我还能从应用中查询什么会导致 1-1 中断?
猜你喜欢
  • 2016-03-23
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
  • 2016-10-22
  • 2020-08-15
  • 2020-05-14
  • 1970-01-01
相关资源
最近更新 更多