Meteor:关闭全部tab时退出登陆

功能描述:在浏览器退出时(全部tab关闭时)退出登陆浏览器

需求来源:支持相似传统网页登陆时的remember me选项并发

背景:Meteor应用中,用户登陆后,会在浏览器的localStorage保存resume token, 因此下次再使用该浏览器打开同一meteor应用时,会自动登陆。有时,咱们但愿应用支持在浏览器退出时(全部tab关闭时)即退出登陆,然而meteor被没有对这项功能的原生支持,须要咱们本身实现。spa

要点:如何检测tab关闭,如何检测全部tab关闭code

如何退出登陆

调用Meteor.logout()blog

如何检测tab关闭

咱们但愿tab关闭时退出登陆,那么咱们得有方法检测tab关闭。咱们能够向浏览器beforeunload事件注册监听。例如:token

$(window).on('beforeunload', function () {
   Meteor.logout();
});

如何检测全部tab关闭

依据meteor的登陆机制,在如何用户在同一浏览器打开多个tab,那么他们的登陆状况是相同的。若是仅依靠上述代码,那么任意tab关闭时,将致使用户退出登陆。咱们但愿的逻辑是,浏览器关闭,或者全部该应用的tab关闭时,才退出登陆。事件

或许有更好的解决方案,这里仅介绍一下个人一种解决方案:利用浏览器的localStorage,记录当前应用打开的tab数目,当关闭tabrem

    $(window).on('load', function () {
        let count = Meteor._localStorage.getItem(openTabCountKey);
        count = count ? Number(count) + 1 : 1;
        Meteor._localStorage.setItem(openTabCountKey, count);
    });

    $(window).on('beforeunload', function () {
        Meteor._localStorage.setItem(openTabCountKey, Number(Meteor._localStorage.getItem(openTabCountKey)) - 1);
    });

这里有几个小的细节须要注意:字符串

  1. 使用Meteor._localStorage而不是window.localStorage以得到更好的兼容性
  2. localStorage存储的全是字符串,因此咱们要进行格式转换
  3. 声明一个常量openTabCountKey
  4. 该操做并发量很是小,暂且忽略了状态同步问题

在记录了tab打开数量以后,咱们能够修正一下上述代码:get

    $(window).on('beforeunload', function () {
        let count = Number(Meteor._localStorage.getItem(openTabCountKey));if (!(count > 0)) {
            Meteor.logout();
        }
    });

擦屁股

有了上述代码,应用应该具备咱们预期的功能:当浏览器关闭时,或全部该应用的tab关闭时,退出登陆。

而然,聪明的你可能会发现,再次打开该应用时,控制台显示一段报错提示:……(大意是你被服务端强制退出登陆)

若是你查看一下Meteor.logout源码,应该能够知道缘由:该方法先调用了服务端方法,在服务端清除相关resume token,而后客户端在回调中再清除本地保存的resume token。

而然,虽然服务端清除了resume token,但咱们没有等到客户端响应就关闭了tab(关闭了应用),因此没办法在回调中执行客户端相关的清理工做。所以,咱们须要显示地、同步地执行客户端清理工做。修正后的代码以下:

    $(window).on('beforeunload', function () {
        let count = Number(Meteor._localStorage.getItem(openTabCountKey));if (!(count > 0) && shouldLogout) {
            Meteor.logout();
            Accounts.makeClientLoggedOut();
        }
    });

Summary

添加一些方法,以支持设置与取消该特性。

相关代码以下:

    /**
     * logout when all tabs are closed
     * @param {Boolean} setIt - default true
     */
    logoutOnClose(setIt = true) {
        if (setIt) {
            Meteor._localStorage.setItem(oncloseLogoutKey, true);
        }
        else {
            Meteor._localStorage.removeItem(oncloseLogoutKey);
        }
    }
    willLogoutOnClose() {
        return Boolean(Meteor._localStorage.getItem(oncloseLogoutKey))
    }
    $(window).on('load', function () {
        let count = Meteor._localStorage.getItem(openTabCountKey);
        count = count ? Number(count) + 1 : 1;
        Meteor._localStorage.setItem(openTabCountKey, count);
    });

    $(window).on('beforeunload', function () {
        Meteor._localStorage.setItem(openTabCountKey, Number(Meteor._localStorage.getItem(openTabCountKey)) - 1);
    });
    $(window).on('beforeunload', function () {
        let count = Number(Meteor._localStorage.getItem(openTabCountKey));
        let shouldLogout = Boolean(Meteor._localStorage.getItem(oncloseLogoutKey));
        if (!(count > 0) && shouldLogout) {
            Meteor.logout();
            Accounts.makeClientLoggedOut();
        }
    });
相关文章
相关标签/搜索