为什么从 Firebase 数据库中检索数据不适用于用户 Auth 规则但适用于匿名规则?
Why retrieving Data from Firebase database doesn't work with user Auth rule But work with anonymous rule?
(注意:用户必须登录才能查看 activity 并且已实施且工作正常)
(更新:我将我的代码更新为工作代码,我希望这能帮助那些在 firebase push() 生成的嵌套推送唯一密钥下努力检索值的人——查看 User_location 下的图片明白我的意思--)
我会非常详细,以确保你们明白我的意思。
首先,我通过如下设置数据库规则在没有用户身份验证的情况下尝试我的代码,(它工作得很好,我能够从 Firebase 检索我的数据并查看它们。)
{
"rules": {
".write": true,
".read": true
}
}
然后,当我按如下方式设置规则时:(出现错误)
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
这是错误消息(应用程序没有崩溃并且 activity 显示空白屏幕):
11-21 04:20:01.424 9820-9820/? W/zygote: Unexpected CPU variant for X86 using defaults: x86
11-21 04:20:01.453 9820-9828/? E/zygote: Failed sending reply to debugger: Broken pipe
11-21 04:20:01.951 9820-9867/? W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-21 04:20:01.978 9820-9867/? W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-21 04:20:02.081 9820-9867/? W/zygote: Skipping duplicate class check due to unrecognized classloader
11-21 04:20:02.700 9820-9876/com.example.msiuser.atyourservice W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
11-21 04:20:05.139 9820-9820/com.example.msiuser.atyourservice W/StaticLayout: maxLineHeight should not be -1. maxLines:1 lineCount:1
11-21 04:20:05.303 9820-9820/com.example.msiuser.atyourservice W/StaticLayout: maxLineHeight should not be -1. maxLines:1 lineCount:1
[ 11-21 04:20:05.342 9820: 9876 D/ ]
SurfaceInterface::setAsyncMode: set async mode 1
11-21 04:20:05.482 9820-9820/com.example.msiuser.atyourservice W/View: requestLayout() improperly called by android.widget.ListView{337754f VFED.VC.. .F....ID 0,207-1080,1260 #7f080079 app:id/list} during layout: running second layout pass
这是我的代码:(layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
我的Javaclass:
public class 地址簿扩展 AppCompatActivity {
private static final String TAG = "AddressBook";
FirebaseDatabase database;
DatabaseReference myRef;
DatabaseReference myRef2;
private String userID;
private ListView liv;
private ArrayList<String> user_addresses = new ArrayList<>();
private ArrayAdapter<String> adapter;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
@Override
protected void onCreate(Bundle savedIntancesState) {
super.onCreate(savedIntancesState);
setContentView(R.layout.activity_addressbook_listview);
liv = (ListView) findViewById(R.id.lv);
mAuth = FirebaseAuth.getInstance();
database= FirebaseDatabase.getInstance();
myRef = database.getReference("User_Location");
final FirebaseUser user = mAuth.getCurrentUser();
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
adapter = new ArrayAdapter<String>(AddressBook.this, android.R.layout.simple_list_item_1, user_addresses);
liv.setAdapter(adapter);
myRef.addChildEventListener(new ChildEventListener() {
@Override
//How to retrieve data under nested push unique key that made by firebase..
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot location : dataSnapshot.getChildren()) {
String value = location.child("location").getValue(String.class);
user_addresses.add(value);
adapter.notifyDataSetChanged();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
for (DataSnapshot location : dataSnapshot.getChildren()) {
String value = location.child("location").getValue(String.class);
user_addresses.remove(value);
adapter.notifyDataSetChanged();
}
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
// User is signed in
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
toastMessage("Successfully signed out.");
}
// ...
}
};
}
@Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
private void toastMessage(String message){
Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}
}
所以基本上正如您在上面的代码中看到的那样,我正在尝试检索 children of child "User_Location",它包含用户唯一的 Uid,它是 child 位置唯一标识。为了在这里清楚地说明我是如何构建数据的:
1- 用户:
2- 位置:
3-User_Location(link 每个用户都有他们的位置,因为一个用户可以保存多个位置)
请告诉我哪里错了..
enter image description here
您的代码附加到 myRef = database.getReference("User_Location")
,但您的规则授予对 /users/$uid
的读取权限。所以读取被拒绝。
要使侦听器正常工作,请确保用户有权读取您附加侦听器的位置。所以:
{
"rules": {
"User_Location": {
".read": "auth.uid !== null"
}
}
}
您可能想试试这个:
{
"rules": {
"User_Location": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
但是将侦听器附加到 /User_Location
仍然会被上述规则拒绝,因为您没有授予对 /User_Location
的读取权限。以这种方式使用安全规则过滤数据是很常见的,但是 rules are not filters. To learn more about this, read some of the many questions about this topic.
(注意:用户必须登录才能查看 activity 并且已实施且工作正常)
(更新:我将我的代码更新为工作代码,我希望这能帮助那些在 firebase push() 生成的嵌套推送唯一密钥下努力检索值的人——查看 User_location 下的图片明白我的意思--)
我会非常详细,以确保你们明白我的意思。 首先,我通过如下设置数据库规则在没有用户身份验证的情况下尝试我的代码,(它工作得很好,我能够从 Firebase 检索我的数据并查看它们。)
{
"rules": {
".write": true,
".read": true
}
}
然后,当我按如下方式设置规则时:(出现错误)
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
这是错误消息(应用程序没有崩溃并且 activity 显示空白屏幕):
11-21 04:20:01.424 9820-9820/? W/zygote: Unexpected CPU variant for X86 using defaults: x86
11-21 04:20:01.453 9820-9828/? E/zygote: Failed sending reply to debugger: Broken pipe
11-21 04:20:01.951 9820-9867/? W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-21 04:20:01.978 9820-9867/? W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-21 04:20:02.081 9820-9867/? W/zygote: Skipping duplicate class check due to unrecognized classloader
11-21 04:20:02.700 9820-9876/com.example.msiuser.atyourservice W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
11-21 04:20:05.139 9820-9820/com.example.msiuser.atyourservice W/StaticLayout: maxLineHeight should not be -1. maxLines:1 lineCount:1
11-21 04:20:05.303 9820-9820/com.example.msiuser.atyourservice W/StaticLayout: maxLineHeight should not be -1. maxLines:1 lineCount:1
[ 11-21 04:20:05.342 9820: 9876 D/ ]
SurfaceInterface::setAsyncMode: set async mode 1
11-21 04:20:05.482 9820-9820/com.example.msiuser.atyourservice W/View: requestLayout() improperly called by android.widget.ListView{337754f VFED.VC.. .F....ID 0,207-1080,1260 #7f080079 app:id/list} during layout: running second layout pass
这是我的代码:(layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
我的Javaclass:
public class 地址簿扩展 AppCompatActivity { private static final String TAG = "AddressBook";
FirebaseDatabase database;
DatabaseReference myRef;
DatabaseReference myRef2;
private String userID;
private ListView liv;
private ArrayList<String> user_addresses = new ArrayList<>();
private ArrayAdapter<String> adapter;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
@Override
protected void onCreate(Bundle savedIntancesState) {
super.onCreate(savedIntancesState);
setContentView(R.layout.activity_addressbook_listview);
liv = (ListView) findViewById(R.id.lv);
mAuth = FirebaseAuth.getInstance();
database= FirebaseDatabase.getInstance();
myRef = database.getReference("User_Location");
final FirebaseUser user = mAuth.getCurrentUser();
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
adapter = new ArrayAdapter<String>(AddressBook.this, android.R.layout.simple_list_item_1, user_addresses);
liv.setAdapter(adapter);
myRef.addChildEventListener(new ChildEventListener() {
@Override
//How to retrieve data under nested push unique key that made by firebase..
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot location : dataSnapshot.getChildren()) {
String value = location.child("location").getValue(String.class);
user_addresses.add(value);
adapter.notifyDataSetChanged();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
for (DataSnapshot location : dataSnapshot.getChildren()) {
String value = location.child("location").getValue(String.class);
user_addresses.remove(value);
adapter.notifyDataSetChanged();
}
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
// User is signed in
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
toastMessage("Successfully signed out.");
}
// ...
}
};
}
@Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
private void toastMessage(String message){
Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}
}
所以基本上正如您在上面的代码中看到的那样,我正在尝试检索 children of child "User_Location",它包含用户唯一的 Uid,它是 child 位置唯一标识。为了在这里清楚地说明我是如何构建数据的:
1- 用户:
2- 位置:
3-User_Location(link 每个用户都有他们的位置,因为一个用户可以保存多个位置)
请告诉我哪里错了..
enter image description here
您的代码附加到 myRef = database.getReference("User_Location")
,但您的规则授予对 /users/$uid
的读取权限。所以读取被拒绝。
要使侦听器正常工作,请确保用户有权读取您附加侦听器的位置。所以:
{
"rules": {
"User_Location": {
".read": "auth.uid !== null"
}
}
}
您可能想试试这个:
{
"rules": {
"User_Location": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
但是将侦听器附加到 /User_Location
仍然会被上述规则拒绝,因为您没有授予对 /User_Location
的读取权限。以这种方式使用安全规则过滤数据是很常见的,但是 rules are not filters. To learn more about this, read some of the many questions about this topic.