Assuming a simple data structure:
-root
-uid
name:string
-uid2
name:string
Is there a way on firebase side(server) to restrict the unique name?
I've seen some solutions like to store names on another node. The problem would be the store action is actually carried out on client side. It is still easy for a registered user to bypass the checking.
Thanks!
Related
I have a situation where a user can create a doc and then share it with a group of other users. They could share it to multiple different groups. I don't know how to set a rule for this.
Here is the database structure:
So in the group you have a list of docs that have been shared to it. My app loads the group that a user is in, then wants to load all the docs in the documents array. I need a way server side to say that this is OK. Up until now only the owner of the doc can read it.
I put a field in each doc that contains ids for each group its shared to. I think I want to say "check if the user is a member of any groups in the sharedToGroups" list but I can't work out how to do that unless I maintain another list somewhere say in the userProfile doc that has a list of circles the user is a member of. Even then I'd be trying to compare 2 lists and I'm not sure I can do that client side.
It would be nice to be able to get the group Id somehow from where the request is being issued from and just see if that is in the sharedToGroups array.
Any help or comments on how this can be achieved would be greatly appreciated, maybe it needs a different db structure.
You can try an approach of this sort:
I am not sure if this will help you but off the top of my head maybe you could enable permissions on firestore for the group document. As in, in the rules, for the group set up a function that validates the user with the user ID stored in the document with the ID attached in the auth via the firebase auth
Therefore, rather than trying to restrict access per document, restrict access per group.
I'm going to answer my own question. Not sure if its the correct protocol here (not a professional programmer or experienced Stack Overflower) but it might help someone.
I ended up adding a field in the user_profiles document that has a list of each group they are in. This list needs to be maintained as I create and add / remove people from groups along with the members list in the group itself.
The benefit of this is that I can use the users id from the request object to get that document from the data base in the security rule. I then have a 'sharedToGroup' array in the doc I'm trying to access and a "inGroups" array in the user_profile that I can access also. Then I use the hasAny operator to compare the two arrays and allow access if the sharedToGroup array has any values from the inGroups array.
My rule becomes:
match /_group/{groupId}{
allow create: if isSignedIn();
allow read: if isOwner()
|| resource.data.sharedToGroup.hasAny(get(/databases/$(database)/documents/user_profiles/$(request.auth.uid)).data['inGroups']);
allow write: if isOwner();
}
Only thing left to do is to secure the user_profiles doc to make sure not even the user can write to it since I don't want someone manually adding groups into their array.
I hope this might help someone someday - like I said I'm a not a pro here so take it with a grain of salt.
I am using firebase as a backend for my Android App. And this app is a social media app where users can post, comment & like. so I am storing user data in user_collection and this collection is secured by security rules where if uid == auth.uid (any user can only access data of himself).
Now in this app when a user post something every user can see this post. And in post_collection I am saving userId in post_doc.
So the problem is I need to show name of user to other users and I have only userId but the problem is a user can't get name of other user by uid beacuse of security rules. now I have to solutions for this please tell me which one is better or you can also suggest any other solutions also?
I can use cloud functions getUserNameById() (Problem : I need to call this function very frequently in feed when user scroll)
I can store name also in post_doc (problem : when user changes his name then It will show old name in old post)
Thanks for you kind help
In a scenario like the one you describe, I would typically store the user name in each post doc. I would also ignore updates to the name, as I think of the user name in the post doc as a historical value: this is the name the user had when they posted this. Now you may want different behavior of course, in which case I recommend reading: How to write denormalized data in Firebase
Your approach with Cloud Functions is fine too, and quite common in some situations. But I tend to only use Cloud Functions for reading data, it the read operation itself is particularly complex, which isn't the case here. In a case like this, I'd recommend coming up with a data model that allows the use-case and security you want.
For example: if you create a collection usernames where each document has the UID as its document ID, and then contains a single field with the username for that UID, you could implement the lookup of the user name through Firestore.
So you could have:
Store the full user profile in /users/$uid.
Store the user name in /usernames/$uid.
Have a Cloud Function that triggers when /users/$uid is written and that updates /usernames/$uid.
The client then has read access to each /usernames/$uid document, or even to the entire /usernames collection in one go if needed.
This way the names can be cached on the client, and continue to work when the app is offline, unlike in your approach with a Cloud Function that looks up the user name.
Consider the solution: whatever public data you need (author name, author userpic link etc) just save it with the post at the time it had created.
So your Message Pojo will looks like:
id
authorName
text
etc..
and just display this name (authorName).
It will be the bad way to go any time to User_collection folder to take the name even if there are would be not strict security (becouse it takes time and document reads)
I have a Google Firebase Realtime Database with the following structure:
project
|
- users
|
- uid_1
|
- name
- age
- ...
|
- uid_2
|
- name
- age
- ...
I'm new with Google Firebase. I can read all db-fields from a specific 'uid'. But how can I collect all names from all unsers? I want to make an file-uploader and to assing the file to an existing user, I want to use a dropdown-menu to select the user.
With the way you have this data structured, you're going to have to write code to query everything under "users", iterate the children, and pull the names out of each child.
Realtime Database doesn't offer any sort of SQL-like projection type query that will get you just the vales of certain children. Or to put it another way, you can't do anything like "select name from users". If getting only the name is a common operation for you, you will need to duplicate only the names into another parent node, and query that new node instead.
The Firebase Admin SDK allows retrieving the entire list of users in batches. But max result is 1000.
Or you can denormalizing your data.
i have a simple question regarding if it's a good practice to use the uid of the FirebaseAuth-Service for relations in other collections as the document index. So on login I get the uid of the FirebaseUser. With that I create an user like so:
Now is that a good practice to use this uid as the index of another document somewhere in another collection like this:
Or is it more common to let the index be generated and add an uid field inside the document so that I can query it with 'uid' equal 'my_uid' for example?
I come from the SQL-side and I don't have that much experience about NoSQL and how to sturcture it well. It would be great if someone could give me an advice here.
This is not a problem at all to reuse the same document ID in different collections, whether this id is a user uid (from Auth) or any other value (including an auto generated Firestore id).
Or is it more common to let the index be generated and add an uid
field inside the document so that I can query it with 'uid' equal
'my_uid' for example?
This is also a common approach, which can be interesting for example if you don't want to display the value of a Firestore document id (for example in an an url like https://www.whatever.com/players/-useruid- or https://www.whatever.com/players/-playername-).
Note however that this can generate some "tricky" side effects: for example if you want to avoid having two user profiles with the same user_name, in order to check that into a Transaction, you need to use the user_name as the id of the documents, since, with the Client SDKs it is not possible to execute a query within a Transaction (you need to define a DocumentReference to pass to the Transaction's get() method).
I am doing the user authentication where I have this case:
Read from vendor_type document and if it returns null(doesn't exist) then continue the transaction,
Create new user using .auth().createUserWithEmailAndPassword(email,password),
Read the new users ID,
Write to vendor_type document some of the new user's detail such as name, surname, userId -->> userId is the problem, how can I create a user and get the ID within a single transaction, can I even do that? ,
Take the newly created ID of the user, and create a new vendor document with that ID.
So far I don't have any code to post because I don't know if this is even gonna work so I didn't start. If you have any idea how to implement this, please let me know. The main issue is getting the user ID while still in the transaction.
At the time of writing, it is not possible to combine in one transaction the creation of a user through the createUserWithEmailAndPassword() method from the Auth service AND a write to the Firestore service.
They are two different services offered by Firestore and therefore you cannot combined calls to these two different services in one transaction.