带有 Vuex 的 Firebase 身份验证 Vue Router Guard 问题

Firebase Authentication Vue Router Guard Issue w/ Vuex

我在 vue 中使用 firebase 身份验证,为了防止仪表板上导航栏中“登录”的初始闪烁(而不是身份验证时登录的用户名),我在 [=31] 中初始化 firebase =] 并将 vue 应用包装在 onAuthStateChanged 函数中。

main.js

initializeApp(firebaseConfig);

const auth = getAuth();
const app = new Vue({
  router,
  store,
  vuetify,
  render: h => h(App)
});
auth.onAuthStateChanged(user => {
  console.log('firedOnAuthStateChanged');
  store.dispatch("setUser", user).then(() => {
    app.$mount('#app');
  });
});

效果很好。我登录,直到用户通过 firebase 身份验证后页面才会加载,我用更新的用户信息更新 vuex 存储(一些来自 firebase,一些来自后端)。

我现在遇到的问题是,我想在路由器中使用 beforeEach 路由守卫,但路由守卫 运行 在 main.js 中触发 authStateChange 之前。因此,用户没有在 vuex 中设置,当我使用存储的用户状态来确定用户是否登录时,它认为他们没有登录,因为 firebase 方法还没有更新它。

authentication.js(来自 store.js 的模块)

setUser({dispatch, commit}, user) {
return new Promise((resolve, reject) => {

  if(user)
  {   
    user.getIdToken().then(token => {
      commit('SET_SESSION_TOKEN', token);
      console.log(token);
      this._vm.$axios.get('/api/user/login',{
          headers: {
              'Authorization': `Bearer ${token}`
          }
      })
      .then((response) => {
          commit('SET_SESSION_USER', response.data);
          resolve(response);
          
      })            
    });
  }
  else
  {
    this._vm.$axios.post('/api/user/logout').then((response) => {
      console.log(response);
      commit('SET_SESSION_USER', null);
      commit('SET_SESSION_TOKEN', null);
    });
    resolve();
  }  
})

},

router.js

router.beforeEach(async (to, from, next) => {
  
  console.log('Is Authenticated:' +store.getters.isAuthenticated);
  console.log('Session User:' +store.getters.getSessionUser);
  if (to.matched.some(record => record.meta.authRequired) && !store.getters.isAuthenticated) {//!userAuth) {
    next({ path: '/login'})
    } else {
      next();
    }
});

我四处搜索,一些解决方案说在路由器中添加你的 firebase onAuthStateChanged。这确实允许路由守卫正常工作,但是重新创建了我在将该方法添加到 main.js 之前遇到的问题 - 页面闪烁并带有预登录信息。我发现其他可能性说你可以在 onAuthStateChanged 方法周围添加一个承诺并从路由器调用它。这可能行得通,但我不确定如何在 main.js 文件中使用 firebase 来实现它,该文件包裹在正在初始化的 vue 应用程序周围。

我想避免设置 cookie 或使用 localstorage 来完成这项工作,我想知道是否有某种方法可以让 firebase、vuex state 和 vue route guards 一起正常运行。

我想出了一个方法来做到这一点。登录和注销正常工作,通知在登录和注销时工作(刷新时根本不工作),用户永久登录(onAuthState 和令牌更新应处理 1 小时超时),并且页面仅在 firebase 登录完成后加载,所以没有闪烁的“登录”而不是用户名。

main.js

initializeApp(firebaseConfig);

const auth = getAuth();

let app;
auth.onAuthStateChanged(user => {
  console.log('firedOnAuthStateChanged)')
  store.dispatch("setUser", user).then(() => {
    if (!app) {
      app = new Vue({
        router,
        store,
        vuetify,
        render: h => h(App)
      }).$mount('#app')
    }
  }); 
});

authentication.js(来自 store.js 的模块)

setUser({dispatch, commit}, user) {
    return new Promise((resolve, reject) => {
      if(user)
      {   
        user.getIdToken().then(token => {
          commit('SET_SESSION_TOKEN', token);
          this._vm.$axios.get('/api/user/login',{
              headers: {
                  'Authorization': `Bearer ${token}`
              }
          })
          .then((response) => {
              commit('SET_SESSION_USER', response.data);
              resolve(response);
              
           })
          .catch(error => {
              dispatch('setSnackbar', {
                color: "error",
                timeout: 4000,
                text: 'Failed verifying token on login.'
              });
              reject();
          });
            
        });
      }
      else
      {
        this._vm.$axios.post('/api/user/logout').then((response) => {
          commit('SET_SESSION_USER', null);
          commit('SET_SESSION_TOKEN', null);
        });
        resolve();
      }  
    })
  }

router.js

router.beforeEach((to, from, next) => {
  const auth = getAuth();
  const user = auth.currentUser;
  if (to.matched.some(record => record.meta.authRequired) && !user) {
    next({ path: '/login'})
    } else {
      next();
    }
});

如果您知道更有效的方法,请告诉我。