D
D
dicem2019-10-26 01:34:41
Vue.js
dicem, 2019-10-26 01:34:41

How to force beforeRouter to wait until firebase confirms authorization?

I am making a simple application based on a series of lessons from https://youtu.be/DlXSA3_lSX4 .
I got to the point where in the routing we check whether the user is logged in and send to the appropriate pages:

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

// Routes
import Home from '@/views/Home'
import TasksPage from '@/views/TasksPage'
import Login from '@/views/Auth/Login'
import Registration from '@/views/Auth/Registration'

import store from '../store'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home,
    beforeEnter(to, from, next) {
      store.getters.checkUser ? next() : next('/login')
    }
  },
  {
    path: '/tasks',
    name: 'tasks',
    component: TasksPage,
    beforeEnter(to, from, next) {
      store.getters.checkUser ? next() : next('/login')
    }
  },
  {
    path: '/login',
    name: 'login',
    component: Login,
    beforeEnter(to, from, next) {
      !store.getters.checkUser ? next() : next('/')
    }
  },
  {
    path: '/registration',
    name: 'registration',
    component: Registration,
    beforeEnter(to, from, next) {
      !store.getters.checkUser ? next() : next('/')
    }
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router


beforeEnter checks checkUser, which at one time in the store module looks like this by default:
store/user.js

import firebase from 'firebase/app'

import User from './user_help'

export default {
  state: {
    user: null
  },
  mutations: {
    setUser(state, payload) {
      state.user = payload
    }
  },
  actions: {
    async registerUser({commit}, {email, password}) {
      commit('clearError')
      commit('setLoading', true)
      try {
        const user = await firebase.auth().createUserWithEmailAndPassword(email, password)
        commit('setUser', new User(user.user.uid))

        commit('setLoading', false)
      } catch (err) {
        commit('setLoading', false)
        commit('setError', err.message)
        throw err
      }
    },
    async loginUser({commit}, {email, password}) {
      commit('clearError')
      commit('setLoading', true)
      try {
        const user = await firebase.auth().signInWithEmailAndPassword(email, password)
        commit('setUser', new User(user.user.uid))

        commit('setLoading', false)
      } catch (err) {
        commit('setLoading', false)
        commit('setError', err.message)
        throw err
      }
    },
    loggedUser({commit}, payload) {
      commit('setUser', new User(payload.uid))
    },
    logoutUser({commit}) {
      firebase.auth().signOut()
      commit('setUser', null)
    }
  },
  getters: {
    user(state) {
      return state.user
    },
    checkUser(state) {
      return state.user !== null
    }
  }
}


To change the user in the state, there is a setUser mutation and the User class that it uses is also imported:
export default class User {
  constructor(id) {
    this.id = id
  }
}

In main.js, before all this business, in fact, the created () method should be processed:
main.js

new Vue({
  router,
  store,
  render: h => h(App),
  created() {
    const firebaseConfig = {
      apiKey: "...",
      authDomain: "...",
      databaseURL: "...",
      projectId: "...",
      storageBucket: "...",
      messagingSenderId: "...",
      appId: "..."
    }
    firebase.initializeApp(firebaseConfig)

    firebase.auth().onAuthStateChanged( user => {
      if (user) {
        this.$store.dispatch('loggedUser', user)
      }
    })
  }
}).$mount('#app')


The essence of the error is that now when I refresh the page with a web application being an authorized user, beforeEnter does not wait until firebase checks me for authorization, it uses the default null value and throws me to the login page. the same story happens with the navigation which I implemented as follows:
Navbar.vue

...
    computed: {
      checkUser() {
        return this.$store.getters.checkUser
      },
      linkMenu() {
        if (this.checkUser) {
          return [
            { name: 'Home', url: '/' },
            { name: 'Tasks', url: '/tasks' }
          ]
        }
        return [
          { name: 'Login', url: '/login' },
          { name: 'Registration', url: '/registration' }
        ]
      }
    }
...


That is, first checkUser receives the default false, processes it according to the current value, and then fixes it reactively after firebase has confirmed the authorization.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
0
0xD34F, 2019-10-26
@dicem

Change the order of actions - first authorizing, then creating a vue instance:

firebase.auth().onAuthStateChanged(user => {
  if (user) {
    store.dispatch('loggedUser', user);
  }

  new Vue(...);
});

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question