Search code examples
firebasegoogle-cloud-platformgoogle-cloud-firestorefirebase-security

firebase security rules check 2 fields in data


according to the docs functions cannot create variables but I need to check two fields for write permissions on my companies collection. I have the documentId stored on my user document as company_slug

So rule #1 for match /companies/{company} { allow write: ... } is

get(/databases/$(database)/documents/users/$(request.auth.uid)).data.company_slug == company

That is fine for read access but I need to check the user.level (1 for admin, 2-n for other levels) whether or not a write is OK.

so rule #2 would be

get(/databases/$(database)/documents/users/$(request.auth.uid)).data.level == 1

So the complete rule would be:

match /companies/{company} {
          allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.company_slug == company;
          allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.company_slug == company && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.level == 1;
}

Which seems very unwieldy and would also "cost" me 2 reads and 1 write for every write request I send, wouldn't it?

Is there any way to optimize this as this seems very hard to maintain as the application grows.


Solution

  • You could use Custom Claims to implement you security needs.

    You would assign two different Claims to each user :

    companyId
    

    and

    userLevel (1, 2, 3, etc)

    and your rules would look like:

    service cloud.firestore {
      match /databases/{database}/documents {
    
        function userIsLevel1() {
            return (request.auth.uid != null) && (request.auth.token.userLevel == 1);
        }
    
        function isCorrectCompany(company) {
            return request.auth.token.companyId == company;
        }
    
        match /companies/{company} {
              allow read: if isCorrectCompany(company);
              allow write: if isCorrectCompany(company) && userIsLevel1();
        }
    
    }
    

    One key advantage of using Custom Claims is that you don't need to read one or more Firestore document(s) for each Security Rules verification.

    You may watch this official Firebase video, starting at 17:49: https://www.youtube.com/watch?v=eW5MdE3ZcAw