Create a document only if it doesn't exist in

2019-04-08 08:22发布

What I am trying to achieve is very simple. I need to create a user entry in the database only if it doesn't exist.

The app flow:

  1. Create a user with Firebase Auth (obtain UID)
  2. Create a user document in the database using UID as the key

The client code (create operation):

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

The firestore rules:

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; 
    }
  }
} 

Additional info:

As you may already know the code doesn't work. Everytime I run the client-side code the current user is completely replaced with a new document. However, if I delete the following line from the rules everything works as expected:

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

But now the question arises, how do I secure data inside user document from unauthorised modifications? Any advice?

3条回答
叛逆
2楼-- · 2019-04-08 08:53

this.db.doc('users/' + uid).set({username: Santa}, {merge: true}) It should merge and not replace. Fields omitted will remain untouched. https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference#set

查看更多
对你真心纯属浪费
3楼-- · 2019-04-08 08:57

If you want to allow creating a document only if it doesn't already exist, just use the allow create rule that you already have. Because you also have an allow update rule, updating the existing data is also allowed.

The following rules should be sufficient:

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

You don't need the exists() call, because allow create only applies if the data does not exist.

Now to your question: You should clarify what you mean exactly. Now only the authenticated user can modify its own record. If you don't want to allow arbitrary data to be written, check for it.

Here are some examples: https://firebase.google.com/docs/firestore/security/rules-conditions#authentication

查看更多
Evening l夕情丶
4楼-- · 2019-04-08 09:07

Use logic in your code, but not in rules. Add addOnCompleteListener to user collection and after get the result do some actions.

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

}

Rules:

match /UsersProfile/{document=**} {
  allow read, write: if request.auth != null;
}
查看更多
登录 后发表回答