android - Permiso de Firebase denegado al leer datos después de la autenticación
firebase-security firebase-realtime-database (3)
Soy nuevo en Firebase. Autentiqué al usuario mediante correo electrónico y contraseña.
final Firebase ref = new Firebase("https://app.firebaseio.com");
ref.authWithPassword("[email protected]", "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) {
}
});
Pero después de la autenticación cuando estoy leyendo los datos, recibo el
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());
}
});
}
Estas son las reglas de Firebase.
{
"rules": {
"users": {
"$uid": {
".read": "auth !== null && auth.provider === ''password''"
}
}
}
}
El modelo de permisos de Firebase solo permite al usuario acceder a los datos a los que usted otorga acceso explícitamente.
Dado que en sus reglas de seguridad, solo le da acceso a
/users/$uid
, el usuario no puede leer desde la raíz
/
.
La documentación de Firebase cubre esto en
"cascada de reglas"
.
Parece que quiere usar reglas de seguridad para filtrar datos, lo cual no es posible con el modelo de seguridad de Firebase. Consulte la sección "las reglas no son filtros" en la documentación de Firebase, así como estas preguntas y respuestas anteriores:
- el permiso de seguridad de firebase no funciona
- las reglas de firebase no funcionan
- Cómo usar las reglas de Firebase para dar solo permiso a ciertos nodos hoja
La solución más simple es permitir la lectura del nodo de
users
:
{
"rules": {
"users": {
".read": "auth !== null && auth.provider === ''password''"
}
}
}
Y luego consulta en ese nivel:
getData(ref.child("users"));
El problema es que Firebase tiene un error, que después de la autenticación, debe esperar hasta que el usuario aparezca en
FirebaseAuth
, y luego puede usarlo.
Lo que hice fue esperar a que apareciera, como
Observable.fromCallable(() -> signInImpl())
.map(this::toFirebaseUser)
.map(this::waitForUserToAppearInAuthenticator)
.flatMap(this::doSomethingInDatabase);
Dónde
@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;
}
Obtuve esta excepción usando un enfoque ligeramente diferente para leer desde mi base de datos, pero así es como resolví el problema.
En primer lugar, las reglas de mi base de datos se veían así:
{
"rules": {
"student": {
"$uid": {
".write": "auth != null && auth.uid == $uid",
".read": "auth != null && auth.uid == $uid"
}
}
}
}
Anteriormente, para escribir en la base de datos de estudiantes, usé este código en mi Actividad:
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>() {
...
});
¿Observa cómo el nombre del niño (estudiante) coincide con el nombre del niño en las reglas de datos de Firebase?
Ahora para leer los datos de este usuario, hice esto:
//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");
}
}
};
Obtuve la excepción de permiso denegado si solo hice:
databaseReference = firebaseDatabase.getReference().child(user.getUid());