我已经实现了 Firebase 实时数据库存在系统,如官方 Firebase 文档中所示。我希望确保数据库安全,以便登录用户只能写入数据库中自己的存在条目。因此,在登录时,用户写入参考路径/auth/{authId}/connections
并同时设置onDisconnect
删除该值。
以下是在 rtdb 中设置存在的 Android 应用程序的代码:
getFirebaseDatabase().goOnline();
DatabaseReference.goOnline();
// Since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
final FirebaseDatabase database = getFirebaseDatabase();
final DatabaseReference myConnectionsRef = database.getReference("/auth/" + getFirebaseAuth().getUid() + "/connections");
// Stores the timestamp of my last disconnect (the last time I was seen online)
final DatabaseReference lastOnlineRef = database.getReference("/auth/" + getFirebaseAuth().getUid() + "/lastOnline");
connectedRef = database.getReference(".info/connected");
presenceChangeListener = connectedRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
DatabaseReference con = myConnectionsRef.push();
// When this device disconnects, remove it
con.onDisconnect().removeValue()
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Add this device to my connections list
// this value could contain info about the device or a timestamp too
con.setValue("ANDROID");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d(TAG, "### Failed to set onDisconnect ###");
e.printStackTrace();
}
});
// When I disconnect, update the last time I was seen online
lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP);
}
}
@Override
public void onCancelled(DatabaseError error) {
Log.w(TAG, "Listener was cancelled at .info/connected");
}
});
我遇到的问题是,如果用户注销,onDisconnect
除非我首先手动断开与 rtdb 的连接,否则不会执行。我假设在实时数据库上运行的代码由于身份验证不再有效而被拒绝。
//If I don't go offline first the record in rtdb will not be removed.
DatabaseReference.goOffline();
AuthUI.getInstance().signOut(this)
.addOnCompleteListener(new OnCompleteListener<Void>() {
public void onComplete(@NonNull Task<Void> task) {
// user is now signed out
Log.d(TAG, "Logged out");
application.clearData();
DatabaseReference.goOffline(); //This doesn't cause a presence update here
finish();
}
});
上面是我正在使用的解决方法,首先告诉数据库goOffline
然后注销。如果用户通过其他方式注销(网络应用程序正在查看是否有多个选项卡正在使用该应用程序,并且其中一个选项卡已注销),则用户将保留未删除的连接。
如果我不打电话给goOffline()
在注销之前,即使我强制关闭应用程序,rtdb 中的连接也不会被删除。
我还验证了如果我将 rtdb 规则更改为".write": "true"
onDisconnect当用户注销身份验证时运行。
我希望我的实时规则是这样的。
{
"rules": {
"auth": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}
我本来希望onDisconnect
当用户的身份验证时,仍然可以执行onDisconnect
被建立。