为什么我在Firebase数据库上被拒绝访问

时间:2019-12-21 02:17:08

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

每当我尝试从数据库中读取(我可以写)时,都会被拒绝权限

  /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
  "rules": {
    "Users": {
      "$user_id":{
        ".read": "$user_id == auth.uid",
        ".write": "$user_id == auth.uid"
      }
    }
  }
}

这是应该检索数据库中每个用户的活动(我有20个)


import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.example.shrinkio.Adapter.UserAdapter;
import com.example.shrinkio.R;
import com.example.shrinkio.model.User;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;
import java.util.List;

public class PeopleFragment extends Fragment {

    private RecyclerView recyclerView;
    private UserAdapter userAdapter;
    private List<User> mUsers;

    EditText search_bar;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_people, container, false);

        recyclerView = view.findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        search_bar = view.findViewById(R.id.search_bar);
        mUsers = new ArrayList<>();
        userAdapter = new UserAdapter(getContext(), mUsers);
        recyclerView.setAdapter(userAdapter);

        readUsers();
        search_bar.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
             searchUsers(charSequence.toString().toLowerCase());
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

        return view;
    }

    private void searchUsers(String s) {
        Query query = FirebaseDatabase.getInstance().getReference("Users").child("user_Id").orderByChild("Name").startAt(s).endAt(s+"\uf8ff");

        query.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                mUsers.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                    User user = snapshot.getValue(User.class);
                    mUsers.add(user);
                }
                userAdapter.notifyDataSetChanged();
            }

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

            }
        });
    }

    public void readUsers(){
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users");
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if ( search_bar.getText().toString().equals("")) {
                    mUsers.clear();
                    for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()){
                        User user = dataSnapshot.getValue(User.class);
                        mUsers.add(user);
                    }

                }            }

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

            }
        });
    }
}

如前所述,在回收者视图中,我应该获得20个用户,但是,没有错误发生,但是活动仍然为空白,一旦我检查了logcat,就会遇到以下错误。

它确实显示为错误,但是我看不到数据库上的帖子或任何用户信息:

W/SyncTree: Listen at /Users failed: DatabaseError: Permission denied

2 个答案:

答案 0 :(得分:0)

您的安全规则要求用户必须先登录,然后才能读取/写入数据库。即使这样,用户也只能在/Users/theirUid下读取或写入自己的节点,其中theirUid是Firebase Authentication首次登录时为其分配的用户ID。

您的代码完全不使用Firebase身份验证。这意味着没有用户登录,因此/Users上的读取操作被拒绝。

您需要进行两项更改:

  1. 使用Firebase身份验证登录用户。有关更多信息,请参见documentation for Firebase Authentication
  2. 将允许已登录用户阅读的内容扩大为/Users,或者将代码缩小为仅读取/Users/theirUid。后者实质上使搜索变得不可能。

如果要允许用户搜索数据,而不是读取所有数据,请考虑在Cloud Functions中实现搜索功能。由于Cloud Functions在受信任的环境中运行,因此它们具有对数据库中数据的完全访问权限。但是,由于您的代码在服务器上运行,因此可以确保用户只能访问您的代码所允许的内容。

答案 1 :(得分:0)

如果您希望能够搜索用户,则需要在/Users级别授予读取访问权限。但是由于实时数据库中的security rules cascade,如果您授予了这样的权限,则更深层次的限制性“ .read”规则将被忽略,从而允许任何用户读取私有用户数据。

"rules": {
  "Users": {
    "$user_id": {
      ".read": "$user_id == auth.uid", // ignored, superseded by /Users/.read rule
      ".write": "$user_id == auth.uid"
    },
    ".read": "auth != null" // logged in users can read everything under /Users
  }
}

相反,我建议将用户数据分为私人用户数据和公共档案数据。公开个人资料将包含非敏感信息,例如显示名称,个人资料图片,用户名,哈希电子邮件地址(用于“通过电子邮件搜索” / Gravatar)等。

"rules": {
  "Users": {
    "$user_id": {
      ".read": "$user_id == auth.uid", // only the owner can read/write their private data
      ".write": "$user_id == auth.uid"
    }
  },
  "Profiles": {
    "$user_id": {
      ".write": "$user_id == auth.uid" // only the profile owner can update their profile
    },
    ".read": "auth != null" // logged in users can read everything under /Profiles
  }
}

在前端,您可以将RecyclerView更改为使用/Profiles