I am building a mobile application using Flutter. For the to-do list feature, I connected it to the firebase real-time database so that when values are added to the application, those are automatically updated in the firebase database. It was successfully done but what I want to implement is storing data separated by users. It is like users have their own separated database in one firebase real-time database.
For example, if person A adds to-do list data, only A can view it and add more data of him when he signs in. And person B and C cannot view and access A's data but only their own data which they added. And they can add data that can be shown to only themselves when they sign in. I searched and checked many documents but couldn't find one that helped me.
Could anyone help me implement this feature? I also want to make sure that whether I need to add some codes of it to the application if I change the database rule.
Below is the current firebase real-time database rule.
{
"rules": {
".read": true,
".write": true
}
}
And this is my todo list code.
class ToDo extends StatefulWidget {
@override
_ToDoState createState() => _ToDoState();
}
class _ToDoState extends State<ToDo> {
final fb = FirebaseDatabase.instance;
@override
Widget build(BuildContext context) {
final ref = fb.ref().child('todos');
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.indigo[900],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => addnote(),
),
);
},
child: Icon(
Icons.add,
),
),
appBar: AppBar(
title: Text(
'Todos',
style: TextStyle(
fontSize: 30,
),
),
backgroundColor: Colors.white,
),
body: FirebaseAnimatedList(
query: ref,
shrinkWrap: true,
itemBuilder: (context, snapshot, animation, index) {
return GestureDetector(
onTap: () {},
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.white,
),
borderRadius: BorderRadius.circular(10),
),
tileColor: Colors.indigo[100],
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red[900],
),
onPressed: () {
ref.child(snapshot.key!).remove();
},
),
title: Text(
snapshot.value.toString(),
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
),
),
),
);
},
),
);
}
}
class addnote extends StatelessWidget {
TextEditingController title = TextEditingController();
final fb = FirebaseDatabase.instance;
@override
Widget build(BuildContext context) {
final ref = fb.ref().child('todos');
return Scaffold(
appBar: AppBar(
title: Text("Add Todos"),
backgroundColor: Colors.indigo[900],
),
body: Container(
child: Column(
children: [
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(border: Border.all()),
child: TextField(
controller: title,
decoration: InputDecoration(
hintText: 'title',
),
),
),
SizedBox(
height: 10,
),
MaterialButton(
color: Colors.indigo[900],
onPressed: () {
ref
.push()
.set(
title.text,
)
.asStream();
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (_) => ToDo()));
},
child: Text(
"save",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
],
),
),
);
}
}
Thank you
CodePudding user response:
You could create a child nodes with users' UID as they as shown below:
todos/
├─ user1/
│ ├─ todoId1
├─ user2/
│ ├─ todoId2
This way you can restrict a user's access to their entries only with the following rules:
{
"rules": {
"todos": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
You'll have to change the DatabaseReference
in your code to the UID node instead of just the todos so any new items pushed will be under that user:
// Use this ref to:
// 1. Fetch all TODOs
// 2. push() new TODO
final ref = fb.ref().child('todos').child(CURRENT_USER_ID);
Checkout the documentation to learn more about security rules.