Reputation: 319
I have a recyclerview in my app which with a get, it retrieves all the documents in a collection. Each document contains the uid of the person who created it. I would like to implement a security rule in which you retrieve only the documents matches the uid of the owner. It looks like quite trivial, but I am not able to make it working.
Database has a structure like this
cars
|
|-documentA
|-documentB
|-documentC
an each document:
documentA
|
|
|-fieldA: aaa
|-fieldB: bbb
|-userId: aklsjdaosjfpasf
Security rules at firestore
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{cars=**}/{carId} {
allow read: if request.auth.uid == resource.data.userId;
allow write: if request.auth.uid != null;
}
}
}
EDIT query:
query = firestore.collection("cars").limit(10L)
Firestore Adapter for make queries for the recyclerview
public abstract class FirestoreAdapter<VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
private static final String TAG = "Firestore Adapter";
private Query mQuery;
private ListenerRegistration mRegistration;
private ArrayList<DocumentSnapshot> mSnapshots = new ArrayList<>();
public FirestoreAdapter(Query query) {
mQuery = query;
}
public void startListening() {
// TODO(developer): Implement
}
public void stopListening() {
if (mRegistration != null) {
mRegistration.remove();
mRegistration = null;
}
mSnapshots.clear();
notifyDataSetChanged();
}
public void setQuery(Query query) {
// Stop listening
stopListening();
// Clear existing data
mSnapshots.clear();
notifyDataSetChanged();
// Listen to new query
mQuery = query;
startListening();
}
@Override
public int getItemCount() {
return mSnapshots.size();
}
protected DocumentSnapshot getSnapshot(int index) {
return mSnapshots.get(index);
}
protected void onError(FirebaseFirestoreException e) {};
protected void onDataChanged() {}
}
Upvotes: 1
Views: 373
Reputation: 1295
Based on the comments, I think this might be the solution. According to the OP, all users should be able to register a car, but only the user who created a car should be able to see it.
The correct permissions in this case would look like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /cars/{carId} {
allow read, write: if request.auth.uid == resource.data.userId;
allow create: if request.auth.uid != null;
}
}
}
For rules pre version 2:
There is also a problem with the permission URL, you can use the following syntax to match all documents in a collection: /cars/{documemts=**}/
, but your path /{cars=**}/{carId}
is invalid, thereofore the rule will never be enforced for your query.
The path /cars/{carId}
will refer to any document in the collection 'cars', storing the name of the document as 'carId'.
Upvotes: 1
Reputation: 83068
You have to note that security rules are not filters, as explained in the documentation:
Once you secure your data and begin to write queries, keep in mind that security rules are not filters. You cannot write a query for all the documents in a collection and expect Cloud Firestore to return only the documents that the current client has permission to access.
With
query = firestore.collection("cars").limit(10L)
you are querying independently of the userId
, hence the problem.
You need to adapt your query with whereEqualTo()
as follows:
//get the value of uid
query = firestore.collection("cars").whereEqualTo("userId", uid).limit(10L)
Upvotes: 2