MiniDev99
MiniDev99

Reputation: 324

Android: realtime Firebase Rules

I would like to know how to secure my rules. I tried to use auth.uid != null in read and write.

But if a new user is trying to login or create new account it won't succeed and gives me permission denied.

I want to secure Users and restrict read for user himself and his data only:

I tried to use auth.uid != null but already reg user won't be able to login, and new users can't create account. So I had to make it true for public write and read. Any solution?

cuz even auth.uid != null , authenticated user can read the entire data of all users not only himself

This is my rules copy:

{
  "rules": {
    ".write": "root.child('Admins').child(auth.uid).exists()",
    "Admins": {
      ".read": true,
      ".write": false
    },
    "Users": {
      ".read": true,
        ".write": true 
    },
    "PrivateWork": {
      ".read": "auth.uid != null",
        ".write": false
    },
    "Likes": {
      ".read": "auth.uid != null",
        ".write": "auth.uid != null"
    },
    "Work": {
      ".read": "auth.uid != null",
        ".write": false
    },
    "videos": {
      ".read": "auth.uid != null",
        ".write": false
    }
  }
}

enter image description here

RegisterActivity:

//Check if num already exist
binding.continueBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (binding.phoneNumBox.getText().toString().isEmpty()) {
            binding.phoneNumBox.setError(getString(R.string.please_enter_phone));
        } else if (binding.phoneNumBox.getText().toString().length() < 6) {
            binding.phoneNumBox.setError(getString(R.string.enter_valid_phone));
        } else {
        DatabaseReference userRef = FirebaseDatabase.getInstance().getReference("Users");
        userRef.orderByChild("phoneNumber")
                .equalTo(binding.phoneNumBox.getText().toString())
                .addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        if (dataSnapshot.getValue() != null) {
                            Toast.makeText(RegPhoneNumActivity.this, getString(R.string.already_exist), Toast.LENGTH_SHORT).show();
                        } else {
                                Intent intent = new Intent(RegPhoneNumActivity.this, OTPActivity.class);
                                intent.putExtra("phoneNumber", binding.phoneNumBox.getText().toString());
                                startActivity(intent);
                            }
                        }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
        }
    }
});

LoginActivity:

//Check if num already exist
binding.loginContinueBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (binding.loginPhoneNumBox.getText().toString().isEmpty()) {
            binding.loginPhoneNumBox.setError(getString(R.string.please_enter_phone_numb));
        } else if (binding.loginPhoneNumBox.getText().toString().length() <= 6) {
            binding.loginPhoneNumBox.setError(getString(R.string.plaese_enter_valid_phone_num));
        } else {
            userRef.orderByChild("phoneNumber")
                    .equalTo(binding.loginPhoneNumBox.getText().toString())
                    .addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            if (dataSnapshot.getValue() != null) {
                                Intent intent = new Intent(PhoneLoginActivity.this, LoginVerifyPhoneActivity.class);
                                intent.putExtra("phoneNumber", binding.loginPhoneNumBox.getText().toString());
                                startActivity(intent);
                            } else {
                                Toast.makeText(PhoneLoginActivity.this, getString(R.string.phone_num_doesnt_exist), Toast.LENGTH_SHORT).show();
                            }
                        }

                        @Override
                        public void onCancelled(DatabaseError databaseError) {

                        }
                    });
        }
    }
});

Upvotes: 1

Views: 170

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

To allow a user to only read their own data, you'll need to:

  1. Use the user's UID as the key for their node.
  2. Secure access as shown in the documentation on content-owner only access.

For the rules that means your Users node becomes this:

"Users": {
  "$uid": {
    ".read": "$uid === auth.uid"
  }
},

And the code to access it then becomes:

userRef.child(FirebaseAuth.getInstance().getCurrentUser().getUID())
       .addListenerForSingleValueEvent(new ValueEventListener() {

While it is also possible to check the phone number of the signed in user against the value of the node in the database, there too the user will have to be signed in already. If that is the case for you, check the documentation on securely querying data.

Upvotes: 1

Related Questions