In Firestore I have 2 collections
A users collection and a periods collection. I need a rule for my period collection : Read and write only by the user who create the period.
users collection look like
periods collection look like
This is what I try with no success
service cloud.firestore {
match /databases/{database}/documents {
function userDoc() {
return /databases/$(database)/documents/users/$(request.auth.uid);
}
match /users/{userId} {
allow read: if true;
allow create, update: if request.auth.uid == userId;
}
match /periods/{id} {
allow read : if userDoc() == request.resource.data.user;
allow write : if userDoc() == request.resource.data.user;
}
}
}
Replace
if userDoc() == request.resource.data.user
with
if userDoc() == request.resource.data.user_id
Other than that your security rule looks correct to me.
The object ‘request.resource.data.user’ doesn’t exist in your periods collection so it should be changed to ‘request.resource.data.user_id’.
Also the read and delete request doesn’t have a ‘request.resource’ object. So for the read and delete request, ‘request.resource.data.user_id’ should be replaced with ‘resource.data.user_id’.
I would suggest you to use more granular rules for write requests i.e. create, update, delete. For more details on firestore rules you can refer to this link.
For your use case please see the below firestore rule sample.
service cloud.firestore {
match /databases/{database}/documents {
function userDoc() {
return /databases/$(database)/documents/users/$(request.auth.uid);
}
match /users/{userId} {
allow read: if true;
allow create, update: if request.auth.uid == userId;
}
match /periods/{id} {
allow read, delete : if userDoc() == resource.data.user_id;
allow update : if userDoc() == request.resource.data.user_id;
allow create : if userDoc() == /databases/$(database)/documents/$(request.resource.data.user_id.path);
}
}
}
Related
I have a collection structure like this.
products {
123456 : {
stock_qty : (Number)
}
}
I want to validate stock quantity to be positive. I have applied following firebase security rule.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
allow write: if request.auth.uid != null;
}
match /products/{document=**}{
allow write: if request.resource.data.stock_qty > 0;
}
}
}
But Still I am able to add products with negative stock_qty.
what I am doing wrong here?
You need to remove this part of your rules:
match /{document=**} {
allow read: if request.auth.uid != null;
allow write: if request.auth.uid != null;
}
This allows all authenticated users to read and write your entire database, regardless of any other rules you have defined.
If any rule gives access to a document, another rule cannot revoke that access.
If you have other queries for other collections that must be protected, you will need rules for those other collections as well.
Setup multiply rules for firebase.
Example with 3 database collections.
Cloud Firestore
On firebase collection of countries, all users should be allowed to read and write.
On firebase collection of cars, only admins are allowed to write.
On firebase collection of airplanes, all authenticated users are allowed to write.
not working documentation:
https://firebase.google.com/docs/rules/basics#cloud-firestore
how to setup rules with correct syntax?
// All public to include countries
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true ;
allow write: if true ;
}
}
// check cars collection
match /databases/{database}/documents/Cars {
// For attribute-based access control, Check a boolean `admin` attribute
allow read: if true ;
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
}
// check airplanes collection
match /databases/{database}/documents/Airplanes {
// Allow only authenticated content owners access
match /{database}/{userId}/{documents=**} {
allow read: if true ;
allow write: if request.auth.uid == userID
}
}
}
You have a few mistakes in your rules.
You have a statement that allows everyone to write every document. When there is more than one match statement that matches the current request, and one of the statements allows the request, the final verdict is ALLOW. Remove the foloving:
match /{document=**} {
allow read: if true ;
allow write: if true ;
}
Firestore is case sensitive. To avoid mistakes, use consistent naming convetion like camelCase or pascal_case.
You have to add a document match variable at the end of match statement
This should work:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == userId;
}
match /cars/{carId} {
allow read: if true ;
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
}
match /airplanes/{airplane} {
allow read: if true ;
allow write: if request.auth != null ;
}
}
}
I'm trying to use a wildcard in my firebase security rules but it's not working like the online documentation describes.
I want to return the entire itineraryList collection but the security rules aren't working.
match /itinerary/{userId=**}/itineraryList/{doc} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId;
}
What is the correct syntax here to give authenticated users access to the entire list?
Update following your comments:
If you want to give read access to any authenticated user to all documents under the itinerary collection (including sub-collections), do as follows:
service cloud.firestore {
match /databases/{database}/documents {
match /itinerary/{docId=**} {
allow read: if request.auth.uid != null;
}
//possibly add another rule for write
}
}
Initial answer:
This is because by doing {userId=**} you are using the "recursive wildcard syntax", see https://firebase.google.com/docs/firestore/security/rules-structure#recursive_wildcards. It will correspond to the "entire matching path segment".
You should do:
service cloud.firestore {
match /databases/{database}/documents {
match /itinerary/{userId}/itineraryList/{doc} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId;
}
}
}
You may also watch this official Firebase video about Firestore security rules, it explains this point, among others: https://www.youtube.com/watch?v=eW5MdE3ZcAw
I need some help making my security rules for firestore work.
These are my firestore rules:
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderID} {
allow read, update: if request.auth.uid == resource.data.buyerId || request.auth.uid == resource.data.sellerId;
}
}
}
my orders collection:
orders: {
sellerId: 'some-id',
createdAt: timestamp,
buyerId: 'some-id'
}
It should return all documents from orders collection which has either buyerId or sellerId equal to authorised user (request.auth.uid).
but the above rule is not working as expected.
firestore collections screenshot
firebase simulator output
That error message is suggesting that the requested document was not actually present in the database. You entered "orders/{orderId}", which looks like you put a wildcard in the Location field in the simulator. That's not going to work. You need to enter the path to an actual document that exists if you want to test your rule that uses its field values.
resource.data: Null - this error happens when you try to create a new entity.
Split write rule, on create and update.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /user/{userId} {
allow read: if request.auth.uid == userId;
function authed() {
return request.auth.uid == userId;
}
allow create: if authed() && request.resource.data.keys().hasOnly(['name']);
allow update: if authed() && request.resource.data.diff(resource.data).changedKeys().hasOnly(['name']);
allow delete: if authed();
}
}
}
I use a collection called "admin" in Firestore to define which users can write new documents (image below).
At moment, it is controled just by software. I would like to add rules to Firestore. I tried the rule below but it didn't work. What would be the correct rules in that case ?
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow write: if get(/admin/{anyDocument}).data.userId == request.auth.uid;
}
}
}
I'd recommend instead having a users collection with an admin field that can be set to true/false. Then you can do something like:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow write: if get(/users/${request.auth.uid}).data.admin == true;
}
}
}
As far i know this is not possible with your current database structure. Because the push key is not accessible in firestore rules unless it is with in the admin node.
One way is to save the admin with their uid as key like admin/userID/data...
now you can access it
allow write: if get(/databases/$(database)/documents/admin/$(request.auth.uid)).data.userId == request.auth.uid;;