首页 文章

Firebase Auth和Vue路由器

提问于
浏览
5

我正在尝试使用firebase验证Vue.js应用程序 .

我有一个问题,如果在登录时尝试直接访问受登录保护的URL,路由器将加载并检查auth状态,然后firebase.js有时间返回auth响应 . 这导致用户被退回到登录页面(当他们已经登录时) .

如何从firebase检索auth状态之前延迟vue-router导航?我可以看到firebase将auth数据存储在localStorage中,是否可以安全地检查它是否作为初步身份验证检查存在?理想情况下,最终结果是在用户通过身份验证时显示加载微调器或其他内容,然后他们应该能够访问他们导航到的页面 .

路由器/ index.js

let router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/example',
      name: 'Example',
      component: Example,
      beforeEnter: loginRequired
    }
})

function loginRequired (to, from, next) {
  if (authService.authenticated()) {
    next()
  } else {
    next('/login')
  }
}

auth.js

import * as firebase from 'firebase'

var config = {
    // firebase config
}

firebase.initializeApp(config)

var authService = {

  firebase: firebase,
  user: null,

  authenticated () {
    if (this.user == null) {
      return false
    } else {
      return !this.user.isAnonymous
    }
  },

  setUser (user) {
    this.user = user
  },

  login (email, password) {
    return this.firebase.auth().signInWithEmailAndPassword(email, password)
      .then(user => {
        this.setUser(user)
      })
  },

  logout () {
    this.firebase.auth().signOut().then(() => {
      console.log('logout done')
    })
  }
}

firebase.auth().onAuthStateChanged(user => {
  authService.setUser(user)
})

export default authService

app.vue

<template>
  <div id="app">
    <p v-if="auth.user !== null">Logged in with {{ auth.user.email }}</p>
    <p v-else>not logged in</p>
    <router-view v-if="auth.user !== null"></router-view>
  </div>
</template>

<script>
import authService from './auth'

export default {
  name: 'app',
  data () {
    return {
      auth: authService
    }
  }
}
</script>

2 回答

  • 3

    Firebase始终在启动时触发身份验证状态更改事件,但不会立即触发 .

    您需要让 authService.authenticated 返回一个承诺,以便等待Firebase完成其用户/身份验证初始化 .

    const initializeAuth = new Promise(resolve => {
      // this adds a hook for the initial auth-change event
      firebase.auth().onAuthStateChanged(user => {
        authService.setUser(user)
        resolve(user)
      })
    })
    
    const authService = {
    
      user: null,
    
      authenticated () {
        return initializeAuth.then(user => {
          return user && !user.isAnonymous
        })
      },
    
      setUser (user) {
        this.user = user
      },
    
      login (email, password) {
        return firebase.auth().signInWithEmailAndPassword(email, password)
      },
    
      logout () {
        firebase.auth().signOut().then(() => {
          console.log('logout done')
        })
      }
    }
    

    您不需要从 signInWith... 承诺调用 setUser ,因为这已经由 initializeAuth 承诺处理 .

  • 2

    我刚刚遇到了同样的问题,最终延迟了Vue对象的创建,直到第一个onAuthStatedChanged .

    # main.js
    // wait for first firebase auth change before setting up vue
    import { AUTH_SUCCESS, AUTH_LOGOUT } from "@/store/actions/auth";
    import { utils } from "@/store/modules/auth";
    let app;
    firebase.auth().onAuthStateChanged(async user => {
      if (!app) {
        if (user) {
          await store.dispatch(AUTH_SUCCESS, utils.mapUser(user));
        } else {
          await store.dispatch(AUTH_LOGOUT);
        }
        app = new Vue({
          router,
          store,
          i18n,
          render: h => h(App)
        }).$mount("#app");
      }
    });
    

    然后在我的路线中,我检查正常,如果他们最终登录路线,我只需将它们推到我的概述页面,这是我的仪表板页面 .

    #router.js
    router.beforeEach((to, from, next) => {
      let authenticated = store.getters.isAuthenticated;
      if (to.matched.some(record => record.meta.requiresAuth)) {
        // this route requires auth, check if logged in
        // if not, redirect to login page.
        if (!authenticated) {
          next({
            name: "Login",
            query: { redirect: to.fullPath }
          });
        } else {
          next();
        }
      } else {
        // doesn't require auth, but if authenticated already and hitting login then go to overview
        if (authenticated && to.name === "Login") {
          next({
            name: "Overview"
          });
        }
        next(); // make sure to always call next()!
      }
    });
    

相关问题