首页 > 解决方案 > 注销后实时数据库onDisconnect未执行

问题描述

我已经实现了 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然后注销。如果用户曾经通过另一种方式注销(Web 应用程序正在查看是否有多个选项卡正在使用该应用程序并且一个已注销),则用户将留下未删除的连接。

如果我在注销之前不调用goOffline(),即使我强制关闭应用程序,rtdb 中的连接也不会被删除。
我还验证了如果我将 rtdb 规则更改为".write": "true"<-这不好,我可以让一切正常工作。这告诉我,onDisconnect当用户注销身份验证时,运行时有一个权限被拒绝。

我希望我的实时规则是这样的。

{
  "rules": {
    "auth": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid",
        ".write": "auth != null && auth.uid == $uid"
      }
    }
  }
}

我希望在设置onDisconnect时仍然能够使用用户的身份验证执行onDisconnect

标签: androidfirebasefirebase-realtime-database

解决方案


附加onDisconnect()处理程序时,您将在 Firebase 服务器上注册延迟写入。附加处理程序时以及触发处理程序时都会检查是否允许写入。而且由于您的用户在触发写入时已注销,因此您的规则会拒绝它。没有配置选项可以更改此行为,因此您必须想出不同的方法。


推荐阅读