Firebase Auth and Vue-router



我正在尝试使用firebase对vue.js应用进行身份验证。

我有一个问题,如果试图在登录时直接访问登录保护的URL,则路由器将加载并在firebase.js之前加载并检查auth状态。这导致用户被弹跳到登录页面(虽然已经登录了(。

如何将VUE-ROUTER导航延迟到从Firebase检索到AUTH状态?我可以看到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>

firebase总是在启动上触发auth状态变更事件,但不是立即的。

您需要使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 Promise处理。

以理查德的回答为基础,对于那些使用常规vue(不是vuex(

的人来说

main.js

//initialize firebase
firebase.initializeApp(config);
let app: any;
firebase.auth().onAuthStateChanged(async user => {
if (!app) {
    //wait to get user
    var user = await firebase.auth().currentUser;
    //start app
    app = new Vue({
      router,
      created() {
        //redirect if user not logged in
        if (!user) {
          this.$router.push("/login");
        }
      },
      render: h => h(App)
    }).$mount("#app");
  }
});

router.js

//route definitions
//...
router.beforeEach((to, from, next) => {
  const currentUser = firebase.auth().currentUser;
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  if (requiresAuth && !currentUser) {
    const loginpath = window.location.pathname;   
    next({ name: 'login', query: { from: loginpath } });
  } else if (!requiresAuth && currentUser) {
    next("defaultView");
  } else {
    next();
  }
});

我只是遇到了同样的问题,最终延迟了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()!
  }
});

您有两个选项:

1(使用 beforerouteenter 来自组件:

export default {
        name: "example",
        ....
        beforeRouteEnter(to, from, next){
            if (authService.authenticated()) {
                next()
            } else {
                next('/login')
            }
        },
}

2(使用 beforeresolve 从路由器。

router.beforeResolve((to, from, next) => {
    if(to.fullPath === '/example' && !authService.authenticated()){
        next('/login')
    }else{
        next()
    }
})

vue路线卫队的生命圈

要延迟验证状态,您需要做的就是

  • a(在安装应用程序之前,请使用firebase auth onauthstatatechanged方法。
  • b(在路由器文件中,在要添加登录保护的父路由
  • 中添加元路由
  • c(使用路由器。向前进行身份验证以及如何将用户重定向到。我将为下面的每种情况提供示例:a(
    firebase.auth().onAuthStateChanged(function(user) {
        console.log(user)
        new Vue({
            router,
            render: h => h(App),
          }).$mount('#app')
        }
    });

阶段b(

    ....
    ....
    ....
    {
        path: "/dashboard",
        name: "dashboard",
        component: Dashboard,
        meta: { requiresAuth: true },//Add this
        children: [
            {
                path: "products",
                name: "products",
                component: Products,
            },
        ],
    ....
    ....
    ....

阶段C(

    router.beforeEach((to, from, next) => {
        const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
        const currentUser = firebase.auth().currentUser
        if(requiresAuth && !currentUser) {
            next("/")
        } else if(requiresAuth && currentUser) {
            next()
        }else{
            next()
        }
    })

我相信你是很好的。

最新更新