使用serviceWorker做浏览器级的单点登陆

818 阅读1分钟

网上关于serviceWorker一般是用于做PWA的,这里介绍的不是这个,如需了解,自行百度

原理:

serviceWorker是一个独立于页面的,浏览器级别的线程

serviceWorker线程可以与页面间通过addEventListener('message',postMessage进行通信

serviceWorker线程中可以获取到所有被此线程控制的浏览器窗口 self.clients.matchAll()

代码解析

  1. 首先页面中初始时要初始化serviceWorker
navigator.serviceWorker
      .register('serviceWorker.js', {
        scope: '/',
      })
      .then(function(registration) {
        ...
  1. 每个页面进入时,通知serviceWorker有新页面打开了,并监听serviceWorker的信息。

页面代码:

navigator.serviceWorker.controller.postMessage({
    type: 'closeOtherClient',
 })

navigator.serviceWorker.addEventListener('message', function(event) {
    if (event.data.oprType && event.data.oprType === 'close') {
      disconnectCBS.forEach(cb => cb())
    }
})
  1. serviceWorker.js代码

serviceWorker收到新窗口打开信号后,去通知其他所有页面执行关闭代码(比如页面上弹框提示用户,您的账号已在别处登陆)

this.addEventListener('message', function(event) {
  const senderId = event.source ? event.source.id : 'unknow'

  if (event.data.type === 'closeOtherClient') {
    self.clients.matchAll().then(function(clients) {
      if (clients && clients.length) {
        clients.forEach(function(client) {
          if (senderId !== client.id) {
            client.postMessage({
              oprType: 'close'
            })
          }
        })
      }
    })
  }
})

---------------------更新---------------------------

其实最近又发现一种更简单的方案:localstorage

上面使用serviceWorker其实解决的就一个问题:浏览器内跨tab通信

localstorage实现跨tab通信的原理是: 修改localstorage时会在所属域名下的浏览器tab内触发一个事件:storage,可以通过window.addEventListener监听此事件

所以如果想通知其他tab,直接改下localstorage,在其他tab上监听到了此事件就可以做处理,这样就完成了跨tab通信

其他方法

当然也可以设置一个定时器轮询localstorage甚至cookie等,在某tab内改了本地存储,其他tab内轮询后发现值变了就可以做处理。但这样就显得很low