当前位置: 首页 > 知识库问答 >
问题:

消防安全规则没有按预期工作

江向阳
2023-03-14

我重新安排了云firestore的安全规则,以防止在集合中重新创建文档。以下是我使用的规则:

match /UserData/{uid}/DAILY_USAGES/{day} {
  allow create: if !exists(/databases/$(database)/documents/UserData/$(request.auth.uid)/DAILY_USAGES/$(day));
  allow read, update: if request.auth.uid == uid;
}

我用这些文档路径和用户凭据在控制台中模拟了这些规则

/UserData/UoeJtUhPpJTi78HouKLIqhcRpfs48/DAILY_USAGES/09-07-2020

如果我创建了一个id为09-07-2020的文档,并使用上述路径进行模拟,则会失败。当我删除文件09-07-2020时,上述模拟工作正常。因此,它在规则模拟器中运行良好。

但当我在应用程序中尝试时,每次尝试都会再次创建文档。因此,如果文档内容以前不同,则会重置为我用于创建文档的默认值。

这是我在android Studio中使用的代码,仅创建一次此文档

DailyUsage usage = new DailyUsage();
        usage.setUsage(0);
        usage.setTime(formatDate(date));
        FirebaseFirestore.getInstance().collection(Constants.USER_DATA_ROOT).document(uid)
                .collection(Constants.FIRESTORE_CHILD_DAILY_USAGES).document(today).set(usage);

我不想检查文档之前是否存在,因为它会减慢ui的速度,并且不能像我预期的那样工作。因此,我尝试使用安全规则来防止复制文档,但不处理应用程序。有人能帮忙吗?

共有2个答案

史英睿
2023-03-14

感谢@DougStevenson和@Emmanuel我清楚地了解了情况。我在想set()触发器总是允许创建安全规则,因为我们使用set()来创建文档和update()来更新文档。然而,这并不完全正确,如果之前有具有相同id的文档,set()触发器允许更新规则。set()也用于使用合并选项进行更新,我不知道这一点。

我的问题是关于只创建一次firestore文档并防止重新创建它。然而,一方面,我还在某些情况下更新此文档。我想防止用默认值0覆盖文档。因此,我更新了规则,并且知道如果值为0,我将阻止更新。

match /UserData/{uid}/DAILY_USAGES/{day} {
      allow create: if !exists(/databases/$(database)/documents/UserData/$(request.auth.uid)/DAILY_USAGES/$(day));
                allow read: if request.auth.uid == uid; 
        allow update: if request.auth.uid == uid && request.resource.data.usage != 0;
    }

在应用程序中,我没有改变任何东西,并像这样使用:

DailyUsage usage = new DailyUsage();
        usage.setUsage(0);
        usage.setTime(formatDate(date));
        FirebaseFirestore.getInstance().collection(Constants.USER_DATA_ROOT).document(uid)
                .collection(Constants.FIRESTORE_CHILD_DAILY_USAGES).document(today).set(usage);

此代码在应用程序启动时触发,如果没有具有相同id的文档,则允许创建安全规则触发并创建文档。但如果存在文档,则安全规则会触发并检查即将到来的资源数据,如果使用值为0,则会阻止更新。在应用程序的代码块中,它在应用程序启动时将值发送为0,因此不允许更新文档中的任何内容。

韶浩皛
2023-03-14

根据文档是否存在,set()方法有两种行为:

如果文档不存在,将创建该文档。如果文档确实存在,其内容将被新提供的数据覆盖,除非您指定数据应合并到现有文档中

这意味着当文档已经存在时,将触发的规则将是update规则,因此您必须更改您的规则:

allow read, update: if request.auth.uid == uid;

在调用set和文档存在时包含必要的逻辑。

您可能想看看这个关于set和update的使用的答案。这里提到了一个可能适合您需要的创建方法,但它不是web API的一部分,不知道您使用的API上是否有该方法。

 类似资料:
  • 我有一个Firestore集合,结构如下: 但是,当我试图保护集合以只允许上面的快照(而不是对集合中其他文档的请求)时,我的权限是不正确的。这是我尝试过的: 我也试过: 它似乎有效,但不允许我访问文档的子集合。我需要rules方法才能工作。 在我列出答案之前,我会给一些时间,以防更有经验的人有更好的解决方案。

  • 基本上,这是注册的用户ID和每个用户订阅的组ID。我想编写一个安全规则,允许只有当用户是当前auth用户时才访问用户配置文件和子集合,根据我对文档的阅读,我认为通配符可以实现这一点... 这样,我就可以很好地读取文档,但是当我尝试读取子集合时,会出现权限错误。我只能通过显式匹配子集合来使它工作... ...所以我的问题是,这两个例子之间有什么区别,我对递归通配符有什么误解?我认为,第一个示例的部分

  • 我在使用R的group_by和SUMMARY函数时遇到了一些问题,我想知道你们是否可以帮我一些忙。我有一张类似的表格: 我试图使用dplyr的group_by和SUMMARY来找到频率列的平均值。下面是我的示例代码: 我所期望的是,一个表格被吐出来,分解按单个类别分组的平均频率,如下所示: 但是,我收到的是一个按类别分组的表,每个类别接收整个表的平均值,如下所示: 有什么线索吗?我应该说我是初学者

  • 我有自定义控制器和spring应用程序,其配置如下: 似乎对于一个一致的用户来说,它工作得很好。但是如果我已经授权(使用oauth2),并且我的会话(或令牌)过期了->spring尝试将我重定向到登录页面。 有趣的是,内置endpoint按预期工作,即使会话过期。

  • 我已经配置了log4j2.xml文件,application.log文件将被创建,它应该每天翻转。 但是在JVM中,applicatoin.log文件在10MB之后会翻转,如果翻转三次,第一个文件会被覆盖。也就是说我随时都application.logapplication-2020-10-16.log.zip. 为什么log4j2(v2.13)即使配置为每日,也会每10MB滚动一次文件?任何在l

  • 我需要一些帮助来制定我的消防安全规则。 以下是我的firestore规则: