Home > Software design >  How to add firebase security rules for Flutter collection that hasn't been created yet
How to add firebase security rules for Flutter collection that hasn't been created yet

Time:02-09

I'm using Firebase Auth and Firestore Database. I'm trying to add security rules to Firebase Database that allow users to read, update, create and delete posts. When I test my rules in the Rules Playground access is denied so I know that I have not written the rules correctly. This is an image of the database prior to adding security rules.

enter image description here

Now that I have added the security rules the posts collection isn't created and I get error messages in the Rules Playground of:

> Simulated write denied 
> Simulated read denied

enter image description here

enter image description here

And I get console error of:

The following _CastError was thrown building CommunityPage(dirty, dependencies: [_InheritedProviderScope<UserProvider?>], state: _CommunityPageState#f5d54): type 'Null' is not a subtype of type 'String' in type cast

In the app all users should be able to create posts to add to their profile. When a user has a newly created account they do not have any posts that exist yet so I am trying to figure out how to include security rules that allow the page where posts will be displayed to appear even though it doesn't have any content when a new user is created. I have reviewed SO threads and Firebase documentation but since I am new to Flutter and Firebase I can't figure things out.

Any help would be greatly appreciated. Thank you.

My StreamBuilder that displays the posts

class TimelineTab extends StatelessWidget {
  const TimelineTab({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
        stream: FirebaseFirestore.instance
            .collection('posts')
            .orderBy('timestamp', descending: true)
            .snapshots(),
        builder: (context,
            AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const AdaptiveCircularProgressCenter();
          } else {
            return ListView.builder(
                itemCount: snapshot.data?.docs.length,
                itemBuilder: (context, index) {
                  return PostCard(
                      snap: snapshot.data?.docs[index].data()
                          as Map<String, dynamic>);
                });
          }
        });
  }
}

My Security Rules

 rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
  
   function isSignedIn() {
    return request.auth != null;
        }
   function isValidUserName() {
    return request.auth != null 
    && exists(/databases/$(database)/documents/users/$(request.auth.uid))
    && request.resource.data.username.size() >= 3
    && request.resource.data.username.size() <= 30
    && request.resource.data.undername is string;   
        }
   
    match /users/{uid} {
    allow create: if isSignedIn();
    allow read: if isSignedIn();
    allow update: if isValidUserName();
    }
    match /posts/{postID} {
    allow read: if isSignedIn() && request.auth.uid == request.resource.data.uid;
    allow create: if isSignedIn() && request.auth.uid == request.resource.data.uid;
    allow update: if isSignedIn() && request.auth.uid == request.resource.data.uid;
    }

   match /admins/{id} {
   allow create, read, update, delete;
   }
   
  }
}

CodePudding user response:

We can see in the Rules Playground that:

  • The read and write rules that are denied use the isSignedIn() function which checks if the request.auth object is not null;
  • But you don't simulate the user's authentication while using the Rules Playground: see the "Authenticated" switch above the "Run" button in the left pane of the Rules Playground

You should activate the authentication simulation in the Rules Playground for your isSignedIn() function to be evaluated to true.

Note that most probably the error shown in the right part of the Playground shows a message corresponding to this problem but we don't see it in your screenshot.


Update following your comment:

Note that request.resource shall only be used in a write rule (see the doc): this probably explains the problem with the read rule (screenshot at the bottom in your question). You have to do:

allow read: if isSignedIn() && request.auth.uid == resource.data.uid

Note that the above rules means that there is a field named uid in the post document.

For the create rule error: are you sure you pass the user's uid as the value of the field named uid in the newly created document?

  •  Tags:  
  • Related