我正在努力保护我的Firestore数据库,并遇到了一张通配符的麻烦。我有一个名为研究
的根级集合,我只想在 status
字段设置为“已发布”时才允许阅读。
我当前的安全规则如下,
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)
}
...
}
}
此安全性规则在请求单个文档时效果很好,但在执行集合级查询时效果很好。我收到错误消息: null值错误。对于“列表”
。我知道Firestore规则不充当过滤器,但是,我相信我的查询只能在状态
字段等于“已发布”的情况下请求文档。
这是我的两个查询:
// 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);
});
});
};
我最初的想法是,我的收集查询是请求将使安全规则失败的文档,但是在凝视查询之后,我认为这是不正确的...
作为测试,我更改了我的安全规则要测试在调试功能。我最终意识到每次我引用 studyID
变量时,支票都会失败。例如,以下匹配语句失败。
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));
}
查看 firestore-debug.log
,如果我运行请求单个文档的查询,我会看到以下记录:
bool_value: true
string_value: "rMxuVTJ0O15qPjMbpEU1"
bool_value: true
但是,运行集合查询时,请从未运行:
bool_value: true
我从不运行进入文档ID通配符,抛出这样的错误。我无法确定这是我的匹配语句还是我的查询是错误,但是对任何帮助表示赞赏。
I am working on securing my Firestore database and am having trouble with a collection wildcard. I have a root-level collection called study
, I want to allow reads only if the status
field is set to "published".
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'
. 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".
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. As an example the following match statement fails.
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:
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. I can't determine if this is an error with my match statement or my query, but any help is appreciated.
发布评论
评论(1)
我不确定您的用例是什么,但是在尝试读取正在访问或阅读的文档中的数据时,您不必使用
get()
。您应该使用 。请参阅下面的Firestore规则:更新:
访问子收集时,您的查询应与您的安全规则匹配。您应该具有根集合的文档ID来访问您的子集合。例如:
安全规则:
上面的示例规则仅允许在
研究中的引用文档
集合中标记为已发布的引用文档时,将允许读取。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. You should useresource.data
instead. See Firestore Rule below: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. E.g:
Security rules:
The sample rule above will only allow reads to the subcollection documents if the referenced document from the
study
collection is tagged as published.