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.
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
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
andwrite
rules that are denied use theisSignedIn()
function which checks if therequest.auth
object is notnull
; - 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?