如何在需要身份验证,firebase数据库规则的字段中允许访问特定字段

时间:2020-05-01 15:37:52

标签: android firebase firebase-realtime-database firebase-security

我想允许访问用户名,以便其他用户可以按用户名搜索用途。

我的应用程序中具有搜索功能,该功能允许用户通过用户名搜索其他用户

Firebase规则

{
  "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
    }
  }
}

这是用户的JSON

{
  "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"
    }

  }
} 

在我的应用程序中,我具有一个允许用户更改其用户名的功能,通过此代码,我试图验证用户名是否由其他用户替换,我通常会访问单个用户信息如果仅为经过身份验证的用户配置Firebase规则,则by child(uid)可以工作,但是为了验证用户名,我不需要对child(uid)进行排序,因为这只会返回当前用户的单个用户,我需要按child(“ users”)。orderBy(“ userName”)进行排序,这会返回PERMISSION DENIED,因为我没有通过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) {

            }
        });
    } 

1 个答案:

答案 0 :(得分:1)

用户要么可以访问整个节点,要么根本就不能访问该节点。无法让他们仅访问每个子节点的一部分。

但是,即使有,您的代码也会有问题:另一个用户可能会在查询运行的时间之间声明该名称,然后您将新的用户名写入数据库。虽然在您的测试中似乎不太可能出现此问题,但在成功的应用程序中,此类问题(称为竞争状况)一定会再次出现并咬住您。

实现唯一性的惯用方式(也是唯一有保证的方式)是使用必须唯一的事物作为数据库列表中的键。因此,对于您而言,这意味着:

  1. 创建一个用户名列表,每个键是一个用户名,每个值是具有该用户名的用户的UID。
  2. 使用事务来确保没有两个用户同时更新同一节点。
  3. 使用安全规则来确保没有人可以覆盖另一个用户已经声明的用户名。

与其在此重复,不如让我指出以前的一些问题,这些问题将在下面详细介绍: