I'm currently building a chat app and I'm having trouble with Firebase rules. I want to limit users from seeing conversations they are not a part of. However, when I try to implement these rules, access seems to be denied even after checking to see if the conversation exists. How do I properly configure Firebase rules to allow users to view only the conversations they are a part of, rather than all conversations in the database?
This is the ruleset I'm trying to implement only for conversations.
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // Allow users to read and write their own participant documents match /conversation/{conversationId}/participants/{userId} { allow read, write: if request.auth.uid == userId; } // Allow users to read and write messages in a conversation they are a participant of match /conversation/{conversationId}/messages/{messageId} { allow read, write: if exists(/databases/$(database)/documents/conversation/$(conversationId)/participants/$(request.auth.uid)); } // Allow users to read and write their own conversation documents match /conversation/{conversationId} { allow read, write: if exists(/databases/$(database)/documents/conversation/$(conversationId)/participants/$(request.auth.uid)); } } }
Access has been denied at the "top level", which is this part:
// Allow users to read and write their own conversation documents match /conversation/{conversationId} { allow read, write: if exists(/databases/$(database)/documents/conversation/$(conversationId)/participants/$(request.auth.uid)); }
I think it has something to do with the way these nested conversations work, but I don't know what I have to change. I tried reading about this in the google firebase documentation but couldn't find anything related to this. If you have any ideas how to fix this please let me know. Thanks!
I've tried getting it to work with multiple "rule sets". It always fails at exists() function.
I also tried this, but that doesn't seem to work either:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function isUserInParticipants(conversationId) { return get(/databases/$(database)/documents/conversations/$(conversationId)/participants/$(request.auth.uid)).data != null; } match /conversations/{conversationId} { allow read, write: if request.auth != null && isUserInParticipants(conversationId); match /messages/{messageId} { allow read, write: if request.auth != null && isUserInParticipants(conversationId); } } } }
This is the query I use in Vue.js:
init() { const storeAuth = useStoreAuth(); conversationCollectionRef = collection(db, 'conversation') conversationCollectionQuery = query(conversationCollectionRef) this.getConversations() }, async getConversations() { this.coversationsLoaded = false getConversationSnapshot = onSnapshot(conversationCollectionQuery, (snapshot) => { console.log('getConversations') console.log(snapshot) this.conversations = [] snapshot.forEach((doc) => { this.getMessagesOfConversation(doc.id) const conversation = { id: doc.id, ...doc.data(), } this.conversations.push(conversation) }) }) this.coversationsLoaded = true },
You have not shared the running query that triggered this failure, but it is important to remember that Firestore rules are not filters .
If your query is like this:
If you expect Firestore to only return conversations where the rule evaluates to
true
, then this won't work. Firestore will discover that some conversation documents will not evaluate totrue
and the entire query will fail .You need to make sure that the query you run that causes the rule to evaluate only looks at conversations where the rule evaluates to true, for example:
You can check the official Firestore rules document中了解更多信息>.