简体   繁体   English

Firestore 安全规则文档 ID 导致 Null 值错误

[英]Firestore security rules document id causing Null value error

I am working on securing my Firestore database and am having trouble with a collection wildcard.我正在努力保护我的 Firestore 数据库,但在使用集合通配符时遇到了问题。 I have a root-level collection called study , I want to allow reads only if the status field is set to "published".我有一个名为study的根级集合,我只想在status字段设置为“已发布”时才允许读取。

My current security rules are as follows我目前的安全规则如下

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
   
  ...

  function isStudyPublished(studyId) {
    return get(/databases/$(database)/documents/study/$(studyId)).data.status == "published";
  }

  ...

  // Match for participant permissioning
  match /study/{studyId}/{document=**} {
    // Deny all requests to create, update, or delete the study
    allow create, update, delete: if false

    // Allow the requestor to read the study if it is published
    allow read: if isStudyPublished(studyId)
  }

  ...

  }
}

This security rule works great when requesting a single document, but not when doing a collection-level query.此安全规则在请求单个文档时非常有效,但在执行集合级别查询时则无效。 I get the error message: Null value error. for 'list'我收到错误消息: Null value error. for 'list' Null value error. for 'list' . Null value error. for 'list' I understand that Firestore rules do not act as a filter, however, I believe my query should only be requesting documents where the status field equals "published".我知道 Firestore 规则不能充当过滤器,但是,我相信我的查询应该只请求status字段等于“已发布”的文档。

Here are my two queries:这是我的两个查询:

// successfully retrieves a single document
export const getStudy: GetStudy = (studyId) => {
  return new Promise((resolve, reject) => {
    getDoc(doc(firestore, COLLECTION_KEYS.STUDY, studyId))
      .then((doc) => {
        resolve(dataToStudy(doc.id, doc.data()));
      })
      .catch((error) => reject(error));
  });
};
// fails to retrieve multiple documents
export const getStudies: GetStudies = (cursor) => {
  const studies: StudyDoc[] = [];
  return new Promise((resolve, reject) => {
    let q = query(collection(firestore, COLLECTION_KEYS.STUDY), where("status", "==", "published"), orderBy(FIELD_KEYS.UPDATED));

    if (cursor) q = query(q, startAfter(cursor));

    getDocs(q)
      .then((snapshot) => {
        snapshot.forEach((doc) => {
          studies.push(dataToStudy(doc.id, doc.data()));
        });

        return resolve([studies, snapshot.docs[snapshot.docs.length - 1]]);
      })
      .catch((error) => {
        return reject(error);
      });
  });
};

My initial thought is that my collection query was requesting documents that would fail the security rules, but after staring at the query I don't think that's true...我最初的想法是我的集合查询正在请求不符合安全规则的文档,但在盯着查询之后,我认为这不是真的......

As a test, I changed up my security rules to test what would pass using the help of the debug function .作为测试,我更改了我的安全规则以测试使用调试功能的帮助会通过什么。 I ended up realizing that the check fails every time I reference the studyId variable.我最终意识到每次引用studyId变量时检查都会失败。 As an example the following match statement fails.例如,以下 match 语句失败。

match /study/{studyId}/{document=**} {
  // Deny all requests to create, update, or delete the study
  allow create, update, delete: if false

  // Allow the requestor to read the study if it is published
  allow read: if debug(debug(true) && (debug(studyId) != null));
}

When looking at the firestore-debug.log , if I run the query that requests a single document I see the following logged:查看firestore-debug.log时,如果我运行请求单个文档的查询,我会看到以下记录:

bool_value: true

string_value: "rMxuVTJ0O15qPjMbpEU1"

bool_value: true

however, when running the collection query the following is logged:但是,在运行收集查询时会记录以下内容:

bool_value: true

I've never run into the document id wildcard throwing an error like this.我从来没有遇到过文档 id 通配符抛出这样的错误。 I can't determine if this is an error with my match statement or my query, but any help is appreciated.我无法确定这是否是我的匹配语句或查询的错误,但感谢您提供任何帮助。

I'm not sure what your use-case really is but you don't have to use get() when trying to read data from the document being accessed or read.我不确定您的用例到底是什么,但是在尝试从正在访问或读取的文档中读取数据时,您不必使用get() You should use resource.data instead.您应该改用resource.data See Firestore Rule below:请参阅下面的 Firestore 规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    function isStudyPublished() {
      return resource.data.status == "published";
    }

    // Match for participant permissioning
    match /study/{studyId}/{document=**} {

      // Deny all requests to create, update, or delete the study
      allow create, update, delete: if false

      // Allow the requestor to read the study if it is published
      allow read: if isStudyPublished();
    }
  }
}

UPDATE:更新:

When accessing your subcollection, your query should be matched with your security rules.当访问您的子集合时,您的查询应该与您的安全规则相匹配。 You should have the document ID of the root collection to access your subcollection.您应该拥有根集合的文档 ID 才能访问您的子集合。 Eg:例如:

// Document-ID refers to study's document
let q = query(collection(db, "study", <DOCUMENT-ID>, <SUBCOLLECTION-NAME>), where(<FIELDNAME>, "==", <STRING>));

Security rules:安全规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /study/{studyId} {
      // Deny all requests to create, update, or delete the study
      allow create, update, delete: if false

      // Do all restrictions here for the study collection.

      function isStudyPublished() {
        return get(/databases/$(database)/documents/study/$(studyId)).data.status == "published";
      }

      // Rules for accessing subcollection of study collection.
      match /subcollection-name/{docId} {
        // Allow read if the document referenced from the study collection is published.
        allow read: if isStudyPublished();

        // Do all restrictions here for study's subcollection.
      }
    }
  }
}

The sample rule above will only allow reads to the subcollection documents if the referenced document from the study collection is tagged as published.如果study集合中的引用文档标记为已发布,则上述示例规则将仅允许读取子集合文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM