访问 Firestore 规则中的父文档字段
Posted
技术标签:
【中文标题】访问 Firestore 规则中的父文档字段【英文标题】:Access parent documents field in Firestore rules 【发布时间】:2018-07-04 11:49:10 【问题描述】:我在 Firestore 中实现了一本食谱书,其中每个用户都可以看到所有用户创建的所有食谱,但只有食谱的原始作者可以编辑或删除食谱。还允许任何用户创建新配方。
我的问题是我无法设置子集合在子集合父文档的字段上“侦听”的权限。
每个配方文档包含三件事。一个名为 name
的字段用于存储配方名称,一个名为 creatorUID
的字段用于存储创建者 uid 的 request.auth.uid
以及一个名为 ingredients
的子集合,其中包含带有一些随机字段的文档。
service cloud.firestore
match /databases/database/documents
function isSignedIn()
return request.auth != null;
match /ListOfRecipes/recipe
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
match /list=**
allow read: if isSignedIn();
// Should return true if recipe.creatorUID has same value as request.auth.uid
allow write: if recipe.creatorUID == request.auth.uid;
问题在于,这些规则仅适用于创建配方文档。由于数据库说,子集合及其文档没有创建
FirebaseError:[code=permission-denied]:权限缺失或不足。 FirebaseError:缺少权限或权限不足。
调用来自 Angular 客户端及其官方库。
【问题讨论】:
你在match /list=**
里面试过allow write: if request.data.creatorUID == request.auth.uid;
吗?
据我所知 request.data 包含要写入的数据,因为我不想写那段数据......或者?......
【参考方案1】:
规则不会级联,因此您需要对规则捕获的文档执行所需的任何检查。
一般来说,x=**
规则通常是错误的,=**
的使用仅用于极其具体的用例。
根据您的问题,我假设您的数据模式是这样的:
/ListofRecipes/recipe_document/List/list_document
在这种情况下,您需要像这样配置规则:
service cloud.firestore
match /databases/database/documents
function isSignedIn()
return request.auth != null;
match /ListOfRecipes/recipe
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
function recipeData()
return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
match /List/list
allow read: if isSignedIn();
allow write: if recipeData().creatorUID == request.auth.uid;
【讨论】:
@Payerl 这是一个很好的解决方案,但是,您应该非常注意这个问题。每次运行recipeData()
函数时,它都会计入您需要付费的读取次数。因此,如果经常写入该子集合,它将很快变得非常昂贵。
有更好的方法吗?
你能确认这仍然有效吗?我感觉最近(实际上是从今天开始)嵌套路径也执行父规则,并且在您的示例中尝试访问 resource.data.creatorUID 时失败。【参考方案2】:
丹上面的回答效果很好!仅供参考,在我的情况下,我只需要根父文档 ID,您可以使用嵌套语句上方的 match 语句中的变量,如下所示:
service cloud.firestore
match /databases/database/documents
function isSignedIn()
return request.auth != null;
match /ListOfRecipes/recipeID
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
match /List/list
allow read: if isSignedIn();
allow write: if recipeID == 'XXXXX';
【讨论】:
您不需要按照 Dan 的recipeData()
函数将其写为 $(recipeID)
吗? recipeID
和 $(recipeID)
都在这里工作,还是只在 recipeID
工作?【参考方案3】:
根据 Dan 的回答,您应该能够通过将 creatorUID 添加到子集合文档中来减少子集合上 update
和 delete
的数据库读取次数。
您必须将 create
限制为仅创建者,并确保设置了 creatorUID。这是我对 Dan 规则的修改:
service cloud.firestore
match /databases/database/documents
function isSignedIn()
return request.auth != null;
match /ListOfRecipes/recipe
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
function recipeData()
return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
match /List/list
allow read: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
allow create: if recipeData().creatorUID == request.auth.uid
&& request.resource.data.creatorUID == request.auth.uid;
【讨论】:
以上是关于访问 Firestore 规则中的父文档字段的主要内容,如果未能解决你的问题,请参考以下文章
如何从Swift中的Cloud FireStore Firebase访问特定字段
使用访问规则中的字段写入 Firestore 时缺少权限或权限不足