身份验证后读取数据时 Firebase 权限被拒绝
Firebase Permission denied when reading data after authentication
我是 Firebase 新手。我使用电子邮件和密码对用户进行了身份验证 -
final Firebase ref = new Firebase("https://app.firebaseio.com");
ref.authWithPassword("app@firebaseio.com", "password", new Firebase.AuthResultHandler() {
@Override
public void onAuthenticated(AuthData authData) {
System.out.println("User ID: " + authData.getUid());
getData(ref);
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
}
});
但是在我读取数据时经过身份验证后,我得到 Permission Denied
。
private void getData(Query ref) {
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
}
这些是 Firebase 规则。
{
"rules": {
"users": {
"$uid": {
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
Firebase 的权限模型只允许用户访问您明确授予访问权限的数据。由于在您的安全规则中,您只授予对 /users/$uid
的访问权限,用户无法从 root /
读取。 Firebase 文档在 "rules cascade".
下对此进行了介绍
您似乎想使用安全规则来过滤数据,这在 Firebase 的安全模型中是不可能的。请参阅 Firebase 文档中的 "rules are not filters" 部分以及之前的问题和答案:
- firebase rules not working
- How to use Firebase rules to only give permission to certain leaf nodes
最简单的解决方案是允许读取 users
节点:
{
"rules": {
"users": {
".read": "auth !== null && auth.provider === 'password'"
}
}
}
然后在该级别查询:
getData(ref.child("users"));
我使用稍微不同的方法从我的数据库中读取时遇到了这个异常,但这就是我解决问题的方法。
首先,我的数据库规则是这样的:
{
"rules": {
"student": {
"$uid": {
".write": "auth != null && auth.uid == $uid",
".read": "auth != null && auth.uid == $uid"
}
}
}
}
早些时候,为了写入学生数据库,我在 Activity:
中使用了这段代码
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.e(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.e(TAG, "onAuthStateChanged:signed_out");
}
// ...
}
};
...
Student student = new Student();
student.setPhoneNumber("+23480547455343");
student.setCountryOfOrigin("Nigeria");
mDatabaseReference.child("student").child(user.getUid()).setValue(student).
addOnCompleteListener(DetailsCaptureActivity.this,
new OnCompleteListener<Void>() {
...
});
请注意 child 姓名(学生)如何与 firebase 数据规则中的 child 姓名匹配?
现在要读取这个用户的数据,我是这样做的:
//Set up an AuthStateListener that responds to changes in the user's sign-in state:
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
user = firebaseAuth.getCurrentUser();
if (user != null) {
databaseReference = firebaseDatabase.getReference().child("student").child(user.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Student student = dataSnapshot.getValue(Student.class);
phoneNumberTextView.setText(student.getPhoneNumber());
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, databaseError.getMessage());
}
});
} else {
Log.e(TAG, "onAuthStateChanged:signed_out");
}
}
};
如果我这样做,我得到了权限被拒绝的异常:
databaseReference = firebaseDatabase.getReference().child(user.getUid());
问题是Firebase有一个BUG,认证后,必须等用户出现在FirebaseAuth
,然后才能使用。
我所做的就是等待它出现,比如
Observable.fromCallable(() -> signInImpl())
.map(this::toFirebaseUser)
.map(this::waitForUserToAppearInAuthenticator)
.flatMap(this::doSomethingInDatabase);
在哪里
@NonNull
private FirebaseUser waitForUserToAppearInAuthenticator(@NonNull final FirebaseUser user) {
final CountDownLatch cdl = new CountDownLatch(1);
final FirebaseAuth.AuthStateListener l = firebaseAuth -> {
final FirebaseUser cu = firebaseAuth.getCurrentUser();
if (cu != null && user.getUid().equals(cu.getUid())) {
cdl.countDown();
}
};
mFirebaseAuth.addAuthStateListener(l);
try {
cdl.await(20, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
mFirebaseAuth.removeAuthStateListener(l);
}
return user;
}
我是 Firebase 新手。我使用电子邮件和密码对用户进行了身份验证 -
final Firebase ref = new Firebase("https://app.firebaseio.com");
ref.authWithPassword("app@firebaseio.com", "password", new Firebase.AuthResultHandler() {
@Override
public void onAuthenticated(AuthData authData) {
System.out.println("User ID: " + authData.getUid());
getData(ref);
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
}
});
但是在我读取数据时经过身份验证后,我得到 Permission Denied
。
private void getData(Query ref) {
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
}
这些是 Firebase 规则。
{
"rules": {
"users": {
"$uid": {
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
Firebase 的权限模型只允许用户访问您明确授予访问权限的数据。由于在您的安全规则中,您只授予对 /users/$uid
的访问权限,用户无法从 root /
读取。 Firebase 文档在 "rules cascade".
您似乎想使用安全规则来过滤数据,这在 Firebase 的安全模型中是不可能的。请参阅 Firebase 文档中的 "rules are not filters" 部分以及之前的问题和答案:
- firebase rules not working
- How to use Firebase rules to only give permission to certain leaf nodes
最简单的解决方案是允许读取 users
节点:
{
"rules": {
"users": {
".read": "auth !== null && auth.provider === 'password'"
}
}
}
然后在该级别查询:
getData(ref.child("users"));
我使用稍微不同的方法从我的数据库中读取时遇到了这个异常,但这就是我解决问题的方法。
首先,我的数据库规则是这样的:
{
"rules": {
"student": {
"$uid": {
".write": "auth != null && auth.uid == $uid",
".read": "auth != null && auth.uid == $uid"
}
}
}
}
早些时候,为了写入学生数据库,我在 Activity:
中使用了这段代码 mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.e(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.e(TAG, "onAuthStateChanged:signed_out");
}
// ...
}
};
...
Student student = new Student();
student.setPhoneNumber("+23480547455343");
student.setCountryOfOrigin("Nigeria");
mDatabaseReference.child("student").child(user.getUid()).setValue(student).
addOnCompleteListener(DetailsCaptureActivity.this,
new OnCompleteListener<Void>() {
...
});
请注意 child 姓名(学生)如何与 firebase 数据规则中的 child 姓名匹配?
现在要读取这个用户的数据,我是这样做的:
//Set up an AuthStateListener that responds to changes in the user's sign-in state:
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
user = firebaseAuth.getCurrentUser();
if (user != null) {
databaseReference = firebaseDatabase.getReference().child("student").child(user.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Student student = dataSnapshot.getValue(Student.class);
phoneNumberTextView.setText(student.getPhoneNumber());
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, databaseError.getMessage());
}
});
} else {
Log.e(TAG, "onAuthStateChanged:signed_out");
}
}
};
如果我这样做,我得到了权限被拒绝的异常:
databaseReference = firebaseDatabase.getReference().child(user.getUid());
问题是Firebase有一个BUG,认证后,必须等用户出现在FirebaseAuth
,然后才能使用。
我所做的就是等待它出现,比如
Observable.fromCallable(() -> signInImpl())
.map(this::toFirebaseUser)
.map(this::waitForUserToAppearInAuthenticator)
.flatMap(this::doSomethingInDatabase);
在哪里
@NonNull
private FirebaseUser waitForUserToAppearInAuthenticator(@NonNull final FirebaseUser user) {
final CountDownLatch cdl = new CountDownLatch(1);
final FirebaseAuth.AuthStateListener l = firebaseAuth -> {
final FirebaseUser cu = firebaseAuth.getCurrentUser();
if (cu != null && user.getUid().equals(cu.getUid())) {
cdl.countDown();
}
};
mFirebaseAuth.addAuthStateListener(l);
try {
cdl.await(20, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
mFirebaseAuth.removeAuthStateListener(l);
}
return user;
}