最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Pattern for Firebase onAuthStateChanged and Navigation Guards - Quasar app - Stack Overflow

programmeradmin7浏览0评论

I am facing an issue in my Quasar app with regards to browser refresh and Firebase authentication.

After a user logs in and then clicks on the browser refresh, then the firebase.auth().currentUser returns null (as this executes asynchronously). This means that when the beforeEach gets executed the currentUser is null and the user is prompted with the logon page. However I see that when the callback to onAuthStateChanged is getting invoked the user is getting set correctly.

Is there any pattern by which, in a Quasar app, the onAuthStateChanged can be used in navigation process so that existing user session is reused?

// Vue-router => index.js
firebase.auth().onAuthStateChanged(user => {
  console.log('onAuthStateChanged Invoked => ' + user);
});

router.beforeEach((to, from, next) => {
  let currentUser = firebase.auth().currentUser; 
  let requiresAuth = to.matched.some(record => record.meta.requiresAuth);

  if (requiresAuth && !currentUser) {
    next('signin');
  } else {
    if (requiresAuth && currentUser.emailVerified === false) {
      next('signin');
    } else {
      next();
    }
  }
});

I am facing an issue in my Quasar app with regards to browser refresh and Firebase authentication.

After a user logs in and then clicks on the browser refresh, then the firebase.auth().currentUser returns null (as this executes asynchronously). This means that when the beforeEach gets executed the currentUser is null and the user is prompted with the logon page. However I see that when the callback to onAuthStateChanged is getting invoked the user is getting set correctly.

Is there any pattern by which, in a Quasar app, the onAuthStateChanged can be used in navigation process so that existing user session is reused?

// Vue-router => index.js
firebase.auth().onAuthStateChanged(user => {
  console.log('onAuthStateChanged Invoked => ' + user);
});

router.beforeEach((to, from, next) => {
  let currentUser = firebase.auth().currentUser; 
  let requiresAuth = to.matched.some(record => record.meta.requiresAuth);

  if (requiresAuth && !currentUser) {
    next('signin');
  } else {
    if (requiresAuth && currentUser.emailVerified === false) {
      next('signin');
    } else {
      next();
    }
  }
});
Share Improve this question edited Apr 11, 2022 at 14:47 benomatis 5,6437 gold badges39 silver badges60 bronze badges asked May 14, 2018 at 6:09 mithrandirmithrandir 1,3234 gold badges19 silver badges39 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

In your main.js, you should listen for onAuthStateChange.

import Vue from 'vue'
import App from './App'
import router from './router'
import firebase from 'firebase'

Vue.config.productionTip = false

let app;
let config = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_PROJECT_ID.firebaseapp.",
  databaseURL: "https://YOUR_PROJECT_ID.firebaseio.",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_PROJECT_ID.appspot.",
  messagingSenderId: "YOUR_MESSAGING_SEND_ID"
};

firebase.initializeApp(config)
firebase.auth().onAuthStateChanged(function(user) {
  if (!app) {
    /* eslint-disable no-new */
    app = new Vue({
      el: '#app',
      template: '<App/>',
      ponents: { App },
      router
    })
  }
});

We only initialize the app only when we are sure Firebase Auth object is ready to use.

I use the firebase.auth().onAuthStateChanged function directly in my router guard like this: I check if the route needs an authenticated user (optional) and then I load the currently logged in user and mit it in my Vuex store. This way the currently logged in user is in my Vuex state before the route guard checks access. Otherwise, especially after a page reload, the user is not yet loaded and the guard redirects to the login page...

...

Router.beforeEach((to, from, next) => {

  let requiresAuth = to.matched.some(record => record.meta.requiresAuth)

  // If route requires auth --> load auth state first from firebase
  if (requiresAuth) {

    firebase.auth().onAuthStateChanged(user => {

      store.mit("user/SET_USER", user);

      let currentUser = firebase.auth().currentUser
      store.mit("user/SET_USER_FULL", currentUser);

      user.getIdToken().then(token => {
        store.mit("user/SET_TOKEN", token)
      });

      if (!user) next('login')
      else next();
    });

  } else next()

})


export default Router

I use Quasar. And this code is in my router/index.js. Don't forget to import your store like this: import store from '../store'

I refactored the whole router/auth thing again. Moved the code to ./boot/firebase.js.

export default async ({ router, store }) => {

// Here goes the firebase.initializeApp(firebaseConfig); 
// ...
const getCurrentUser = () => {
    return new Promise((resolve, reject) => {
      const unsubscribe = firebase.auth().onAuthStateChanged((userFirebase) => {
        // Do some store stuff...
        store.mit("user/SET_USER", userFirebase);
        unsubscribe();
        resolve(userFirebase);
      }, reject);
    });
  }

  router.beforeEach(async (to, from, next) => {

    const requiresAuth = to.matched.some(record => record.meta.requiresAuth);

    if (requiresAuth && !await getCurrentUser()){
      next({ name: 'login' });
    } else if (!from.name) {
      // Load user also on a full page reload on pages which do not require auth...
      await getCurrentUser();
      next();
    } else {
      next();
    }
  });
发布评论

评论列表(0)

  1. 暂无评论