How to store data that is specific to users with firebase? - android

On the application I am developing, the user creates their account with e-mail and password but how can I make data specific to the user? For example, in my application a user can gain points by completing certain tasks. So when a user completes a task, I need to update their points and store it on the database so they can gain points overtime and use them to redeem awards. Here is what I think I am supposed to do, but I am unsure if I have to add anything to the rules or not.
Note: Every user's point amount is supposed to be unique to that specific user

If you want users to only be able to read/write their own data, you'll want to store that data under the user's UID. From the Firebase documentation on securely accessing user data:
Another common pattern is to make sure users can only read and write their own data:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}

👍 yup looks good, just be careful about who has access to write to that document.

Related

Android | Firestore Rules | Check if username & phone already exists

I want to check if the user's username and phone number is unique. I have implemented it using
FirebaseFirestore.getInstance().collection("Users").whereEqualTo("phone",ph).get().addOnCompleteListener(...);
This is my firestore rule:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: true;
allow write: if request.auth.uid != null;
}
match /Users/{userID} {
allow update: if request.auth.uid == userID
&& (request.resource.data.username == resource.data.username
|| isUserNameAvailable(request.resource.data.username)
);
}
}
The code works fine with no issues. I am checking this before the signInWithCredential method and hence the request.auth.uid will always be null. To make the code work ill have to keep allow read: true;
But, now i am getting this warning
We've detected the following issue(s) with your security rules:
any user can read your entire database
Is there any workaround to prevent this?
This is a common mistake developers make when using usernames. You gave anyone permission to read your whole database. And even if you manage to put that to only read Users anyone could read all your users data.
I would recommend to remove the first allow read:true and write rules for each path as they should be. Also create a separated collection just for usernames and save all of them there like /usernames/${username} and /phones/${phone}. If the need to be saved together you can do that to.
That way you can very easy check without any query if a username or phone exists by just checking if that path exsists in your database.
You can very easy sync the users collection with those two and even write security rules that prevent creating users in the collection that have a username that already exists in the usernames collection.

How to prevent a user in Firestore from creating and reading more than one document without using Firebase authentication?

I have a Firestore database that I only use to check if the user has passed the app's trial period. It has one collection called "users" and each document in it has its Document ID value set to the Settings.Secure.ANDROID_ID of the user it belongs to and it has one field inside it that's the timeStamp of when the user installed the app.
Currently the security rules are like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, create: if true;
}
}
}
I'm not using Firebase authentication because I don't want the user to have to login to Firebase in order to use the app.
Is there a way to set the security rules so that each user can only create and read one single document (his own)? I don't want a hacker to create millions of documents or to read other documents.
You definitely shouldn't rely on client side security. Firebase Authentication has a type called Anonymous. This will allow your user to start using the app in a way that you can control with security rules. If/ when they are ready to sign up, you can convert a user to a conventional sign-in provider.
https://firebase.google.com/docs/auth/android/anonymous-auth
The user ID assigned to the user of an Android app with Anonymous Authentication, persists until the app is uninstalled (I believe).
You can then add security rules to ensure that a user is only able to read/write to a single document in a collection or only read/write documents which they have created.
Write one document per user
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
Only read/write documents created by the user
match /mydocs/{mydocId} {
allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.authorId;
allow create: if request.auth != null && request.auth.uid == request.resource.data.authorId;
}
Rules are not filters
With these rules, you will not be able to simply fetch all documents from the collection and only view those which match the user.
Get the user document
db.collection("users").document(userId).get()
Get documents authored by the user
db.collection("mydocs")
.whereEqualTo("authorId", userId)
.get()

How can I restrict users to retrieve only their data from Cloud Firestore?

I'm building an app with Kotlin. In the app, the user can sign up and log in. After the user log in, the user adds some text and pictures, and these data is successfully added to the firebase cloud store and displayed in the app as a list. However, this list can be accessed by anyone registered on the app.
What I want to do is how users can only see their own data. So I don't want users to see each other's data. I just want every user to see their own added data. I think that I need to change Cloud Firestore rules. How do I set permission to specific document?
I'm new to this field, Thank you !
My firebase Cloud Store rules;
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match/Notes/{noteId}{
allow read, write: if request.auth.uid != null ;
}
}
}
this is my firebase cloud store screen shot
it's done by settings up the rules. You can read more here: https://firebase.google.com/docs/database/security#section-overview

Firebase - Predefined User list & Phone Number Authentication

I am working on one the Android APP & want to integrate it with the Firebase & it's Realtime Database. I have a list of 1000 users(Excel) with details like EmpId, EmpName, Team, Mobile Number, etc.
I want to restrict my APP only to the users from this list & also want to authenticate them using the mobile number present in the list against there name.
Can I use Firebase Auth for the above requirement & if yes, how to do that?
If with FireBase Auth, this is not possible what is the alternative solution?
Please help.
Firebase Authentication only allows the users to identify themselves. What you're describing is limiting what users are allowed to use your app, which is known as authorization, and Firebase Authentication doesn't handle that.
Luckily you tagged with firebase-realtime-database too, and authorization is definitely built into that. What I'd usually do is create a top-level node in the database that contains the UID of users that are allowed to use the app:
"allowedUsers": {
"uidOfUser1": true,
"uidOfUser2": true
...
}
Then in other security rules you'll check if the user's UID is in this list before allowing them access to data, with something like:
{
"rules": {
"employees": {
".read": "root.child('allowedUsers').child(auth.uid).exists()",
"$uid": {
".read": "auth.uid === $uid && root.child('allowedUsers').child(auth.uid).exists()"
}
}
}
}
With these rules:
Allowed users that are signed in can read all employee data.
But they can only modify their own employee data.
Of course you'll want to modify these rules to fit your own requirements, but hopefully this allows you to get started.
A few things to keep in mind:
The UID is only created once the users sign up in Firebase Authentication. This means you may have to map from the email addresses you have to the corresponding UIDs. You can either do this by precreating all users, do it in batches, or use a Cloud Function that triggers on user creation to add the known users to the allowedUsers list.
Alternative you can store the list of email addresses in the database. Just keep in mind that somebody could sign in with somebody else's email address, unless you require email address verification. Oh, and you can't store the email address as a key in the database as-is, since . characters are not allowed, so you'll have to do some form of encoding on that.
Also see:
How do I lock down Firebase Database to any user from a specific (email) domain? (also shows how to check for email verification)
Restrict Firebase users by email (shows using encoded email addresses)
firebase realtime db security rule to allow specific users
How to disable Signup in Firebase 3.x
Firebase - Prevent user authentication
I know it's late but for anyone who may be referencing this question, my recommendation is blocking functions. You essentially create a Firebase Cloud Function that can accept or deny requests to make an account. Here's what it could look like:
const functions = require('firebase-functions');
exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
var allowedUsers = ['johndoe#stackoverflow.com'];
// if they are not in the list, they cannot make an account
// throwing this error will prevent account creation
if(allowUsers.indexOf(user.email) == -1) throw new functions.auth.HttpsError('permission-denied');
});
This way is better in my opinion because the security rules doesn't have to reference the database. Instead, the security rules can allow requests from any authenticated user, because the only authenticated users are ones allowed by this function.

prevent a user from writing data to firestore if data exist

I am making an android app that when a user register an account on firebase, he saves his email, phone number and password. but when he wants to login, he uses his phone number and password. Because of that requirement I must also make the phone number unique There are a number of ways too do this but my options are limited because the database is already being used by a working system and me making changes to it will cause the other system not to work. The best way to solve my problem without affecting the other system is by modifying the rules to prevent a user from adding an phone number that already exist.
My database structure is like this
users {
userID {
name: "John"
phone: "2342222"
address: "23rd Avenue"
email: "email#mail.com"
}userID 2 {
name: "Mark"
phone: "2342222"
address: "5th Avenue"
email: "email#mail.com"
}
}
Now my rules look like this
service cloud.firestore {
match /databases/{database}/documents {
match /Users/{anything=**} {
allow write: if auth != null && !data.exists() && data == request.auth.uid;
}match /Users/{userId} {
allow read: if request.auth.uid == userId;
// I need a rule maybe here that will allow me write phone number to the database
// If the number doesn't exist in my entire Users database.
}match /user-compare/{anything=**} {
allow read: if true;
}
}
}
Ive tried
allow write: if request.auth.uid == userId && !request.resource.data.phone in resource.data.phone;
I want to make sure that a user can only read and write data inside its user ID, but my rules should be the one to prevent duplicate data not the source codes because due to the way the other system is setup, if multiple users have the same phone number, it will crash, and right now my app is the only way to make multiple users with the same phone number.
I know I can create a new collection to holder the numbers and then check if the number exist there for the registration process, but if anyone uses the other system to register, the numbers will not appear in this new collection.
The best way is if I can write a rule. My problem is a bit different from what I've seen and I hope I'm explaining properly. any help would be appreciated, thanks.
I couldn't solve it with rules no matter what I tried but Using Firebase Admin SDK will allow a developer write/edit/view information in Authentication section of the Service and this will allow you make the changes and validate them. You can learn more Here. This can be added as a dependency on the app but Due to the nature of the service I didn't feel that It'll be safe giving users access to an app with admin privileges. But this is a solution when you have the application for example in the office and users only have access to it in a save environment and can be used to add more functionality for staffs or authorized member's use.
For me, what solved my security concerns was to install the Admin SDK on a server. For my problem this can be used in two ways. I can make a custom authentication found Here and use that to sign in users using their phone number and password. But what I chose to do was make a simple API to take the phone number and check if there's any email address associated with it. if Yes retrieve the email and use that together with the password and sign in with email and password. so basically it uses the usual email and password sign in, but the user input their number and password instead. This was what worked for me and I hope it helped someone in a similar position.

Categories

Resources