VueJS + Firebase Auth + Route Guards - проблема синхронизации / условия гонки - PullRequest
0 голосов
/ 07 октября 2018

При интеграции Firebase Auth в мое приложение Vue я недавно натолкнулся на проблему, когда вошедший в систему пользователь при обновлении страницы не будет распознаваться как вошедший в систему (и, следовательно, перенаправляется на страницу входа при попытке доступа к защищенному маршруту).
Это связано с тем, что исходный обратный вызов firebase.auth().onAuthStateChanged(...) не был возвращен до того, как охранник маршрута оценил состояние.

Существует несколько предложенных решений, но ни одно из которых не показалось мне чистым.Наиболее заметным, по-видимому, является задержка фактического монтирования приложения путем перемещения new Vue(...).$mount('#app') внутри обратного вызова onAuthStateChanged().
Так как в большинстве случаев первоначальное представление не требует входа пользователя в систему (или может бытьСам путь входа в систему) не должно быть необходимости откладывать монтирование всего приложения до тех пор, пока не вернется обратный вызов firebase.

Я думаю, что мог бы найти лучшее решение, но был бы признателен за некоторую обратную связь, если вы сможетепроблема с этим подходом или возможность его дальнейшего улучшения.

Примечание. Я использую глобальное хранилище состояний Vuex для управления состоянием приложения.

Я инициализирую обратный вызов firebase onAuthStateChanged() в main.js в хуке жизненного цикла created компонента App:

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 голосов
/ 07 октября 2018

В вашем файле 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()    
})

Это работает как для предотвращения посещения страницы, так и для удаления пользователя, если он не авторизован, пока он находится на странице.Я сам пользуюсь этим на одном из своих сайтов, и у меня до сих пор с этим не было проблем

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...