仅当 Firebase Firestore 中不存在文档时才创建文档

Posted

技术标签:

【中文标题】仅当 Firebase Firestore 中不存在文档时才创建文档【英文标题】:Create a document only if it doesn't exist in Firebase Firestore 【发布时间】:2018-04-03 23:06:23 【问题描述】:

我想要实现的目标非常简单。只有当它不存在时,我才需要在数据库中创建一个用户条目。

应用流程:

    使用 Firebase Auth 创建用户(获取 UID) 使用 UID 作为键在数据库中创建用户文档

客户端代码(创建操作):

this.db.doc('users/' + uid).set(username: Santa)

firestore 规则:

service cloud.firestore 
  match /databases/database/documents 
    match /users/uid 
      allow create: if 
        request.auth != null && 
        request.auth.uid == uid && 
        !exists(/databases/$(database)/documents/users/$(uid));
      allow update: if request.auth != null && request.auth.uid == uid; 
    
  
 

其他信息:

您可能已经知道代码不起作用。每次我运行客户端代码时,当前用户都会被一个新文档完全替换。但是,如果我从规则中删除以下行,一切都会按预期工作:

allow update: if request.auth != null && request.auth.uid == uid;

但现在问题出现了,如何保护用户文档中的数据免受未经授权的修改?有什么建议吗?

【问题讨论】:

我会考虑为此使用 firebase 函数 - 而不是客户端修改用户集合。有一个“auth”触发器,可让您在创建新用户时执行 stuf。 【参考方案1】:

this.db.doc('users/' + uid).set(username: Santa, merge: true) 它应该合并而不是替换。省略的字段将保持不变。 https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference#set

【讨论】:

【参考方案2】:

在代码中使用逻辑,而不是在规则中。将 addOnCompleteListener 添加到用户集合中,并在获得结果后执行一些操作。

getUsers.document(userUID).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() 
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> doc) 
     if(!doc.getResult().exists())
        //add new user
    
                       

规则:

match /UsersProfile/document=** 
  allow read, write: if request.auth != null;

【讨论】:

同意依赖代码,而不是逻辑的安全规则。【参考方案3】:

如果您希望仅在文档尚不存在时才允许创建该文档,只需使用您已有的allow create 规则即可。因为您还有一条allow update 规则,所以也允许更新现有数据。

以下规则就足够了:

service cloud.firestore 
  match /databases/database/documents 
    match /users/uid 
      allow create: if request.auth != null && request.auth.uid == uid;
    
  
 

您不需要exists() 调用,因为allow create 仅适用于数据不存在的情况。

现在你的问题:你应该澄清你的确切意思。现在只有经过身份验证的用户才能修改自己的记录。如果您不想允许写入任意数据,请检查它。

这里有一些例子: https://firebase.google.com/docs/firestore/security/rules-conditions#authentication

【讨论】:

提供的链接不再有效试试这个:firebase.google.com/docs/reference/security/storage 2021年还有另一种解决方案,继续滚动【参考方案4】:

我曾经使用过它并且它有效。基本上我确保用户通过request.auth != null 登录,然后我检查请求的资源是否为空。如果资源已经存在,则表示用户存在。

我添加了allow update,以防您只希望用户更改自己的数据。

match /users/document 
      allow create: if request.auth != null && resource == null;
      allow update: if request.auth != null && request.auth.uid == resource.data.author_uid;

【讨论】:

【参考方案5】:

您现在可以使用create 方法完成此操作:

create(data) → Promise.&lt;WriteResult&gt;

使用提供的对象值创建一个文档。如果文档存在于其位置,这将导致写入失败。

DocumentReference.create

Transactions 也可以做得更好:

create(documentRef, data) → Transaction

创建由提供的 DocumentReference 引用的文档。如果指定位置存在文档,则该操作将使事务失败。

Transaction.create

【讨论】:

以上是关于仅当 Firebase Firestore 中不存在文档时才创建文档的主要内容,如果未能解决你的问题,请参考以下文章

cleanup() 在使用 Firebase Firestore onSnapshot 的 useEffect() 中不起作用

Flutter Web 在 Firebase 托管中不起作用

从 Cloud Functions for Firebase 中的 Firestore 触发器获取用户 ID?

流和 firebase 状态不佳的问题:DocumentSnapshotPlatform 中不存在字段

Cloud Firestore 安全规则 -(读取、写入)

如何使用云功能删除 Firestore 中的文档