VueJS + Firebase Auth + Route Guards-同步问题/竞赛情况

时间:2018-10-07 07:27:43

标签: firebase vue.js vuejs2

在将Firebase Auth集成到我的Vue应用程序中时,我最近偶然发现了一个问题,其中页面刷新上的登录用户将不会被识别为已登录(因此在尝试访问受保护的路由时会重定向到登录页面)。
这是由于以下事实:在路由守卫评估状态之前,firebase.auth().onAuthStateChanged(...)的初始回调尚未返回。

有几种建议的解决方案,但对我来说似乎都不干净。最突出的似乎是通过在new Vue(...).$mount('#app')回调内移动onAuthStateChanged()来延迟应用程序的实际安装。
由于在大多数情况下,初始视图不需要用户登录(或者可能是Login路由本身),因此无需将整个应用的安装延迟到firebase回调返回之前。

我想我可能已经找到了一个更好的解决方案,但是如果您发现此方法有任何问题或者可以进一步改进,我将不胜感激。

注意:我使用Vuex全局状态存储来管理应用程序状态。

我在App组件的onAuthStateChanged()生命周期挂钩中的main.js中初始化firebase created回调:

new Vue({
  router,
  store,
  render: h => h(App),
  created() {
    firebaseApp.auth().onAuthStateChanged((user) => {
      if(!this.$store.getters.firebaseInitialized)
        this.$store.commit('firebaseInitialized')
      if (user) {
        if(!this.$store.authenticated || this.$store.getters.loggedInUser.uid != user.uid)
          this.$store.dispatch('logIn', user)
      }
    })
  }
}).$mount('#app')

处于该状态的firebaseInitialized布尔值会跟踪firebase的初始化状态,默认为false,并且仅在该第一个true回调中被设置为onAuthStateChanged

router.js内,我现在创建一个“轮询承诺”,它检查所说的firebaseInitialized并等待初始化完成(或超时),然后再检查用户的身份验证状态:

function ensureFirebaseIsInitialized() {
  let timeout = 5000;
  let start = Date.now();
  return new Promise(function (resolve, reject) {
    (function waitForFirebaseInit(){
      if (store.getters.firebaseInitialized) 
        return resolve();
      else if((Date.now() - start) >= timeout) 
        return reject(new Error('Firebase initialize timeout'))
      setTimeout(waitForFirebaseInit, 30);
    })();
  });
}

现在可以在router.beforeEach中使用此承诺:

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    ensureFirebaseIsInitialized().then(() => {
      if(store.getters.authenticated) {
        next()
      }
      else {
        next('/login')
      }
    }).catch((error) => {
      console.log('firebase not initialized')
      next('/login')
    })
  } 
  else {
    next()
  }
})

这种方法是否有我不知道的问题,或者可以进一步改进吗?

1 个答案:

答案 0 :(得分:0)

只需在您的Router.js文件中添加

router.beforeEach((to,from,next) => {
  if(to.matched.some(record => record.meta.auth)){
  firebase.auth().onAuthStateChanged((user) => {
    if(!user)
    {
      next({
        path: '/'

      })
    } else {
      next() 
    }
  })}else next()    
})

这既可以防止页面访问,也可以在用户未经授权时将其赶出该页面。我自己在自己的一个网站上使用了它,到目前为止,还没有问题