0

I want to allow access to user name so other users can search uses by user name.

I have a search feature in my app that allows users to search other users by user name

Firebase Rules

{
  "rules": {
    "users": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth.uid != null",
        ".write": "auth.uid != null"
      },

    },
    "chat": {
      "messages": {
        ".write": true,
        ".read": true
      }
    },
    "app-settings": {
      ".write": true,
      ".read": true
    }
  }
}

Here is JSON of users

{
  "app-settings" : {
    "app-Available" : true,
    "version" : "4"
  },

  "users" : {
    "uid" : {
      "blocked" : false,
      "email" : "gamatiaihab@gmail.com",
      "profilePhotoUrl" : "https://lh3.googleusercontent.com/a-/AOh14Gi6eXrdLfZTQH0B7GvoTxhqBHoVFUUTibK3QKfrfA=s96-c",
      "uid" : "uid",
      "userName" : "gamatiaihab"
    }

  }
} 

In my app, I have a feature that allows the user to change their user name, with this code I'm trying to validate the user name checking if it's takin by other user or not, I normally access the single user information by child(uid) this works if firebase rules are only configured for authenticated users, but in order to validate the user name I need to not order the by child(uid) because this will return only single user which is the current user, I need to order by child("users").orderBy("userName") and this returns PERMISSION DENIED because i didn't pass child(uid)

  private void validateUserName(final String chatUserName){
        mEditChatUserNamePr.setVisibility(View.VISIBLE);
        mDb = FirebaseDatabase.getInstance().getReference().child("users");
        mDb.orderByChild("userName")
                .equalTo(chatUserName)
                 .addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if (dataSnapshot.getValue() != null){
                    mEditChatUserNamePr.setVisibility(View.GONE);
                    mChatUserNameInput.setError("User name not available");
                }else {
                    updateUserName(chatUserName);

                }


            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    } 
  • There is quite some information missing here. Please add: 1) the JSON of `/users` (as text, no screenshots). You can get this by clicking the "Export JSON" link in the overflow menu (⠇) on your [Firebase Database console](https://console.firebase.google.com/project/_/database/data). 2) the rules as text, instead of a screenshot, 3) the code that shows the operation you want to allow, and the result you expect out of that code. – Frank van Puffelen May 01 '20 at 15:42
  • I have updated my post, thank you @FrankvanPuffelen – Aihab Gmati May 01 '20 at 16:15
  • Thanks for that update. Now what's the problem with this code? What specific line doesn't do what you expect it to do, when you step through it in a debugger? – Frank van Puffelen May 01 '20 at 16:36
  • I have explained everything above the java code @FrankvanPuffelen Thank you – Aihab Gmati May 01 '20 at 18:08

1 Answers1

1

A user either has access to a complete node, or they don't have access to the node at all. There is no way to give them access to only part of each child node.

But even if there was, your code would have a problem: another user might claim the name between the time your query runs, and you write the new user name to the database. And while this problem may seem unlikely in your testing, in a successful app this type of problems (known as a race condition) is guaranteed to come back and bite you.

The idiomatic (and only guaranteed) way to implement uniqueness is to use the thing that must be unique as the keys in a list in the database. So in your case that'd mean:

  1. Creating a list of usernames, with each key being a username, and each value being the UID of the user with that username.
  2. Using a transaction to ensure no two users are updating the same node at the same time.
  3. Using security rules to ensure that nobody can overwrite a username that was claimed by another user already.

Instead of repeating more here, let me point you to some previous questions where this was covered in more detail:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807