最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Setting Firebase Firestore security rules so only users can CRUD their own data and all else is ignored - Stack Ove

programmeradmin1浏览0评论

I have an app that is designed so authenticated users via Google only have access to their own data with no "social" features. I want to know the security rules for the below criteria.

Let's say I have 5 collections and one of them is called "todos" and the data mirrors the other collections in that it has a field for the authenticated users uid. The typical document looks something like this:

Todos

todo:{
  title:"some titled",
  body:"we are the world , we are the children",
  uid:"2378y4c2378rdt2387btyc23r7y"  
}

Some other collection

thing:{
  name:"some name",
  content:"Some content",
  whatever:"whu-eva",
  uid:"2378y4c2378rdt2387btyc23r7y"  
}

I want the authenticated Google user to be able to CRUD any data that has said users uid in the uid field. I want all other data to be inaccessible to the logged in user.

I want to know how to create rules for this scenario.

I'm mulling through the documentation now but I figure I might be able to save some time by asking. I do not have specific roles for the app.

As a side note, is their a feature in Firebase to automatically bind an authenticated Google users uid to documents created while they are logged in? (I am assuming the answer is no and I was planning on manually grabbing the uid in my app and setting it on the client prior to document creation).

Thank you.

Update

I tried using the code that Klugjo posted below.

When I try to test it in the simulator I get an error.

Here is my collection and a screenshot of the error.

Here is something else I tried:

Based on everything I've read it seems like the following code should work - but it doesn't. I've supplemented the key "userId" in place of " uid" that is written in the object data at the top of this post. I changed the key to distinguish it from the uid.

service cloud.firestore {
  match /databases/{database}/documents {
    match /todos/{id} {
    allow read: if request.auth.uid == request.resource.data.userId;
    allow create, update, delete:
        if request.resource.data.userId == request.auth.uid;
      }
    }
  }

I've created a video where I try to GET and CREATE a document. I don't think I am using the testing feature correctly.

Video

;feature=youtu.be

EDIT

I have it working when I test with a hard-coded request.auth.uid. In the image below I hardcoded "test" as the request.auth.uid.

My problem now is that I would really like to know how to test it in the rules editor without hard-coding this information.

Edit

Here is a video demo of the problem using a real app.

;feature=youtu.be

I have an app that is designed so authenticated users via Google only have access to their own data with no "social" features. I want to know the security rules for the below criteria.

Let's say I have 5 collections and one of them is called "todos" and the data mirrors the other collections in that it has a field for the authenticated users uid. The typical document looks something like this:

Todos

todo:{
  title:"some titled",
  body:"we are the world , we are the children",
  uid:"2378y4c2378rdt2387btyc23r7y"  
}

Some other collection

thing:{
  name:"some name",
  content:"Some content",
  whatever:"whu-eva",
  uid:"2378y4c2378rdt2387btyc23r7y"  
}

I want the authenticated Google user to be able to CRUD any data that has said users uid in the uid field. I want all other data to be inaccessible to the logged in user.

I want to know how to create rules for this scenario.

I'm mulling through the documentation now but I figure I might be able to save some time by asking. I do not have specific roles for the app. https://firebase.google.com/docs/firestore/solutions/role-based-access

As a side note, is their a feature in Firebase to automatically bind an authenticated Google users uid to documents created while they are logged in? (I am assuming the answer is no and I was planning on manually grabbing the uid in my app and setting it on the client prior to document creation).

Thank you.

Update

I tried using the code that Klugjo posted below.

When I try to test it in the simulator I get an error.

Here is my collection and a screenshot of the error.

Here is something else I tried:

Based on everything I've read it seems like the following code should work - but it doesn't. I've supplemented the key "userId" in place of " uid" that is written in the object data at the top of this post. I changed the key to distinguish it from the uid.

service cloud.firestore {
  match /databases/{database}/documents {
    match /todos/{id} {
    allow read: if request.auth.uid == request.resource.data.userId;
    allow create, update, delete:
        if request.resource.data.userId == request.auth.uid;
      }
    }
  }

I've created a video where I try to GET and CREATE a document. I don't think I am using the testing feature correctly.

Video

https://www.youtube.com/watch?v=W7GZNxmBCBo&feature=youtu.be

EDIT

I have it working when I test with a hard-coded request.auth.uid. In the image below I hardcoded "test" as the request.auth.uid.

My problem now is that I would really like to know how to test it in the rules editor without hard-coding this information.

Edit

Here is a video demo of the problem using a real app.

https://www.youtube.com/watch?v=J8qctcpKd4Y&feature=youtu.be

Share Improve this question edited May 18, 2020 at 21:58 William asked May 16, 2020 at 4:55 WilliamWilliam 4,58818 gold badges66 silver badges117 bronze badges 1
  • Hi, William. You cant make this working with changing rules. I recommend using the firebase functions. So in function, you can get uid of account, and get all todo lists and filter by uid. Anyway client cannot get all todo lists and they will get only filtered data. – ericobi Commented May 24, 2020 at 14:24
Add a comment  | 

3 Answers 3

Reset to default 15 +100

Here is a sample secure rule set for your requirements.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    match /users/{id}/{u=**} {
      allow read, write: if (isSignedIn() && isUser(id));
    }

    match /todos/{id}/{t=**} {
      allow read, write: if (isSignedIn() && isUserOwner());
    }

    match /{document=**} {
      allow read, write: if false;
    }



    function isSignedIn() {
      return request.auth != null;
    }

    function isUser(uid) {
      return uid == request.auth.uid;
    }

    function isUserOwner() {
      return getResourceData().uid == request.auth.uid;
    }

    function getResourceData() {
        return resource == null ? request.resource.data : resource.data
    }

  }
}

All documents are publicly inaccessible.

The rests will be decided based on the data already saved in DB and / or the data being sent by the user. The key point is resource only exists when reading from DB and request.resource only exists when writing to DB (reading from the user).

Documents under todos can be read and written only if they have a saved uid which is the same as the sent request's uid.

Documents under users can be read and written only if their document id is the same as the sent request's uid.

isSignedIn() function checks if request is authorised.

isUser(id) function checks if id matches the authorised request's uid.

isUserOwner() function checks if document's uid matches the authorised request's uid.

I think what you are looking for is the "resource" parameter in the security rules: https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation

Try something like:

service cloud.firestore {
  match /databases/{database}/documents {
    match /todos/{id} {
      allow read, write: if request.auth.uid == resource.data.userId;
    }
  }
}

EDIT:

Subcollection strategy

If you change your DB to look like the following:

/users/{userId}/todos/**

then you could allow users to read/write anything under their own document with the following rule:

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

This would have the advantage of not needing to introspect the contents of the data which I believe might count against your read quota.

You are looking for something like this

service.cloud.firestore {
  match /databases/{database}/documents {
    match /todos/{userId} {
      allow read, update, delete: if request.auth.uid == userId;
      allow create: if request.auth.uid != null;
    }
  }
}

match /todos/{userId} makes the userId variable available in the rule condition

request.auth.uid matches the auth'd user uid

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论