Firebase 中的 onDisconnect() 不可靠

Fir*_* OS 5 firebase firebase-authentication firebase-realtime-database

我在 JavaScript 中编写了以下简单的存在代码(基于https://firebase.google.com/docs/database/web/offline-capabilities#section-sample):

var app = firebase.initializeApp(config);
var mainRef = app.database().ref();
var session = null;
var connected = false;

function do_sessionSubscribe(subscription) {
    if (!subscription.entry) {
        subscription.entry = subscription.parent.push(true);
        subscription.entry.onDisconnect().remove();
    }
}

function do_sessionUnsubscribe(subscription) {
    if (subscription.entry) {
        subscription.entry.remove();
        subscription.entry = null;
    }
}

mainRef.child(".info/connected").on("value", function(snap) {
    connected = snap.val() === true;
    if (session) {
        if (connected) {
            do_sessionSubscribe(session.subscription);
        } else {
            // workaround
            //do_sessionUnsubscribe(session.subscription);
        }
    }
});

function closeSession() {
    if (session) {
        do_sessionUnsubscribe(session.subscription);
        session = null;
    }
}

function openSession(uid) {
    session = { uid: uid, subscription: { parent: mainRef.child("session/user/" + uid), entry: null } };
    if (connected) {
        do_sessionSubscribe(session.subscription);
    }
}

app.auth().onAuthStateChanged(function(user) {
    closeSession();
    if (user && user.uid) {
        openSession(user.uid);
    }
});
Run Code Online (Sandbox Code Playgroud)

安全规则:

"session": {
    "user": {
        "$uid": {
            ".read": "auth.uid === $uid",
            ".write": "auth.uid === $uid",
            "$session": {
                ".validate": "newData.val() === true"
            }
        }
    },
}
Run Code Online (Sandbox Code Playgroud)

这个想法是,用户的每个活动连接将/session/user/$uid/$session在连接/登录时创建,并在断开/注销时删除它。

因此,为了获得在线用户列表,/session/user使用shallow=true.

问题是有时一个会话没有被清理干净并且/session/user/$uid永远停留在下面。然后将其解释为用户是否一直在线。

我发现为了轻松重现该问题,只需阻止对 securetoken.googleapis.com 的访问(我使用 Google 身份验证),等待一个小时并关闭浏览器即可。

我试图通过在断开连接时调用 remove() 来解决这个问题。一旦客户端重新连接,这就会清理陈旧的会话(这太晚了,但迟到总比没有好......)。但是,当用户在失去 Internet 连接后关闭它的浏览器,然后身份验证令牌在套接字超时之前过期时,陈旧的会话将永远存在。

  1. 当用于注册 onDisconnect() 操作的 auth 令牌已过期时,在检查安全规则期间使用 auth.uid 的什么值?
  2. 如何在不影响安全性的情况下使这个在线系统完全可靠?