android - 在处理 Firestore 规则时,我无法检查文档中是否存在字段
问题描述
我正在开发一个包含测验文档的应用程序 Firestore 数据库。每个文档都可能有一个名为 peopleCanAccess 的字符串数组字段。
我想在规则中做什么?如果文档具有此字段 (peopleCanAccess),则 peopleCanAccess 中唯一存在的人可以阅读该文档。如果此字段不存在,则所有经过身份验证的人都可以访问它。
我试过了:
function existingData() {
return resource.data;
}
function isAuthenticated() {
return request.auth != null;
}
function getUid() {
return request.auth.uid;
}
function fieldExists(data, field) {
return !isUndefined(data, field) && !isNull(data, field);
}
function isUndefined(data, field) {
return !data.keys().hasAll([field]);
}
function isNull(data, field) {
return data[field] == null;
}
match /quiz/{quizID}{
allow read : if
(isAuthenticated() && existingData().owner == getUid())
|| (isAuthenticated() && !('peopleCanAccess' in existingData().keys()))
|| (isAuthenticated() && getUid() in existingData().peopleCanAccess)
// !fieldExists(resource.data, 'peopleCanAccess');
...
}
这些规则无法正常工作。
示例:ID 为 tcsFStMdplOJSyZsluJBLHeOuJs1 的用户可以访问上图中提到的测验,尽管他未在 peopleCanAccess 字段中列出
询问:
db.collection("quiz")
.whereEqualTo("id", quizId)
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if (queryDocumentSnapshots.isEmpty()){
}else {
QuizItem quizItem = queryDocumentSnapshots.getDocuments().get(0).toObject(QuizItem.class);
accessedQuiz.postValue(quizItem);
}
}
});
解决方案
最后,我找到了解决方案,
我在 Rules Playground 中检查了规则,并没有发现我的规则有任何问题。它工作正常问题出在我的客户端查询中。我在文档中找到了这个:
在编写查询以检索文档时,请记住安全规则不是过滤器——查询是全部或全部。为了节省您的时间和资源,Cloud Firestore 会根据其潜在结果集而不是所有文档的实际字段值来评估查询。如果查询可能返回客户端无权读取的文档,则整个请求将失败。
注意:您可以将读取规则分解为获取和列出规则。get 规则适用于单个文档的请求,list 规则适用于查询和集合请求。
我是如何解决我的问题的:
1- 打破读写规则:
match /quiz/{quizID}{
allow get : if
(isAuthenticated() && getUid() in existingData().peopleCanAccess)
||
(isAuthenticated() && !checkIfExistsInKeys(existingData(), 'peopleCanAccess'))
allow list : if
(isAuthenticated() && getUid() == existingData().owner)
allow create : if (isAuthenticated() && getUid() == existingData().owner);
allow update : if (isAuthenticated() && getUid() == existingData().owner);
allow delete : if (isAuthenticated() && getUid() == existingData().owner);
}
2-更改我的客户查询以检索一个文档:
db.collection("quiz")
.document(quizId)
.get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (!documentSnapshot.exists()){
}else {
QuizItem quizItem = documentSnapshot.toObject(QuizItem.class);
accessedQuiz.postValue(quizItem);
}
}
});
推荐阅读
- c - #define 预处理器指令值
- c - `"
" 想使用 VS Code 和 macOS Catalina 访问 Documents 文件夹中的文件 - reactjs - 有没有办法使用样式组件/ JSX 作为标记元素?
- c# - Blazor 浏览历史记录和页面引荐来源网址
- google-apps-script - 将特定范围的单元格导出为 PDF - Google 表格
- javascript - 无法读取 d3.js 的未定义属性“序数”
- css - 取消鼠标移出动画
- aws-lambda - 向 AppSync 模型属性添加唯一约束
- php - PHP设置权限和删除文件夹-文件
- r - 线性回归 - 使用预测时未找到对象