Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What rule do I need to allow access to users data in Firestore?

I'm learning Firestore and have built an angular app. I'm using Firebase authentication and having trouble figuring out the rules to use to allow a user access to their data. So for example a products collection which each product has a userId which is actually their email address.

Example: enter image description here

The current rule I have is as follows and is not working (i've tried everything I can figure based on docs, stackoverflow, etc.):

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userEmail} {
        allow read, write: if request.auth != null;
    }
    match /products/{userId}{
        allow read, write: if request.auth.uid.userEmail == userId
    }  
  }
}

The only thing i've done that does work (i.e. I get all products back) is if I do a match/{document=**) which opens it up to anyone which is NOT what I want. :)

Any ideas?

Edit: Incase someone is wondering about the angular code. Again, if I set the rule to allow anything I DO get data back. If I restrict it, so far I get nothing. So, I know the code works (getAll) thus it must be the rules are not right.

Edit: I updated the code to write the users email to the console just before requesting all products data from the store. It successfully output the user's email.

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { AngularFireAuth } from '@angular/fire/auth';
import { Product } from '../models/product.model';

@Injectable({
  providedIn: 'root'
})
export class ProductsService {

  private dbPath = '/products';

  productsRef: AngularFirestoreCollection<Product>;

  constructor(public afAuth: AngularFireAuth, private db: AngularFirestore) {
    this.productsRef = db.collection(this.dbPath);
  }

  getAll(): AngularFirestoreCollection<Product>{
    this.afAuth.authState.subscribe(user => {
      console.log('Dashboard: user', user);

      if (user) {
          let emailLower = user.email.toLowerCase();
          console.log("Email: " + emailLower);
      }
  });

    return this.productsRef;
  }

  create(product: Product): any {
    return this.productsRef.add(product);
  }

  update(id: string, data: any): Promise<void>{
    return this.productsRef.doc(id).update(data);
  }

  delete(id: string): Promise<void> {
    return this.productsRef.doc(id).delete();
  }
}
like image 757
slashbrackets Avatar asked Dec 18 '21 03:12

slashbrackets


People also ask

How to set rules for Firestore database?

To set up and deploy your first set of rules, open the Rules tab in the Cloud Firestore section of the Firebase console. Write your rules in the online editor, then click Publish.

What file should be used for firestore rules firestore rules?

json // is a file used to define indexes for you Firestore queries.

How do I access firestore data?

There are two ways to retrieve data stored in Cloud Firestore. Either of these methods can be used with documents, collections of documents, or the results of queries: Call a method to get the data. Set a listener to receive data-change events.

What are the rules for Firebase?

How do they work? Firebase Security Rules work by matching a pattern against database paths, and then applying custom conditions to allow access to data at those paths. All Rules across Firebase products have a path-matching component and a conditional statement allowing read or write access.


1 Answers

I think there is some issue with the security rules built. You can refer to the Firestore security rules to learn more about writing rules and for testing your rules you can refer documentation where mentioned :

Cloud Firestore provides a rules simulator that you can use to test your ruleset. You can access the simulator from the Rules tab in the Cloud Firestore section of the Firebase console. The rules simulator lets you simulate authenticated and unauthenticated reads, writes, and deletes.

a) From the screenshot of the Firestore database products collection, the document ID appears to be an auto-generated alphanumeric sequence. So below match rules are going to match document ID (auto-generated) in {userEmail} & {userId} variables instead of the user email or user ID as the variable name suggests.

 match /users/{userEmail}
 match /products/{userId}

You may of course create the Document IDs to have email addresses rather than auto generated sequences in which case above match conditions might work as expected.

b) The usage of request.auth.uid.userEmail is incorrect. The correct way to refer to email from a user's request authentication state is "request.auth.token.email". You can read about the request.auth & resource variable references on Firestore public docs -documentation1 & documentation2 to use correct syntax.

c) Below are some corrections made to the security rules. This should work.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userDocId} {
        allow read, write: if request.auth != null;
    }
    match /products/{productDocId}{
        allow read, write: if request.auth.token.email == resource.data.userId
    }
  }
}
like image 166
Divyani Yadav Avatar answered Oct 11 '22 10:10

Divyani Yadav