Skip to content

Instantly share code, notes, and snippets.

@codeBelt
Last active October 13, 2023 13:13
Show Gist options
  • Save codeBelt/415882a3a4eb4298e4a3ecae592cdf19 to your computer and use it in GitHub Desktop.
Save codeBelt/415882a3a4eb4298e4a3ecae592cdf19 to your computer and use it in GitHub Desktop.
Firestore rules function examples

// https://angularfirebase.com/lessons/firestore-security-rules-guide/

// https://medium.com/@jek.bao.choo/my-firestore-security-rules-learning-notes-14316400f160

Scope Rules to Specific Operations Rules can be enforced on various read/write operations that occur in a clientside app. We can scope rules to each of the follow read operations.

allow read - Applies to both lists and documents. allow get - When reading a single document. allow list - When querying a collection. Write operations can be scoped as follows:

allow create - When setting new data with docRef.set() or collectionRef.add() allow update - When updating data with docRef.update() or set() allow delete - When deleting data with docRef.delete() allow write - Applies rule to create, update, and delete. Request vs Resource Firestore gives us access to several special variables that can be used to compose rules.

request contains incoming data (including auth and time) resource existing data that is being requested This part is confusing because a resource also exists on the request to represent the incoming data on write operations. I like to use use helper functions to make this code a bit more readable.

// Check if document is exists
function documentIdExists() {
return exists(/databases/$(database)/documents/users/$(request.auth.uid));
}
// Check if userId exists in the document
function userExistsInDocument() {
return resource.data.userId == request.auth.uid;
}
// Check if email exists in the document
function userExistsInDocument() {
return resource.data.email == request.auth.token.email;
}
service cloud.firestore {
match /databases/{database}/documents {
function hasRoleOf(role) {
return get(/databases/$(database)/documents/user/$(request.auth.uid)).data.roles[role];
}
function isOneOfTheseRoles(roles) {
return request.resource.data.roles.keys().hasAny(roles) == false;
}
match /beer/{beerId} {
allow read;
allow write, update, delete: if request.auth.uid != null;
}
match /beerOnTap/{beerTapId} {
allow read;
allow write, update, delete: if request.auth.uid != null;
}
match /user/{userId} {
allow read: if isOneOfTheseRoles(['admin', 'editor']);
allow create: if request.auth.uid != null;
allow update, delete: if hasRoleOf('admin') == true;
}
}
}
// https://firebase.google.com/docs/firestore/security/rules-query
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || request.auth.uid == resource.data.author;
// Only story authors can write
allow write: if request.auth.uid == resource.data.author;
}
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's authors can write to a story
allow write: if request.auth.uid == resource.data.author;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment