Vuejs在异步身份验证状态请求上路由导航保护

时间:2018-04-03 03:44:47

标签: javascript vue.js firebase-authentication vue-router vuex

我使用firebase在我的vuejs应用中进行身份验证。在我的根(main.js)vue组件中。

  created() {
    auth.onAuthStateChanged((user) => {
      this.$store.commit('user/SET_USER', user);
      if (user && user.emailVerified) {
        this.$store.dispatch('user/UPDATE_VERIFIED', {
          userId: user.uid,
        });
        // SUCCESSFUL LOGIN
        this.$router.replace('dashboard');
      } else if (user && !user.emailVerified) {
        this.$router.replace('verify');
      }
    });

基本上,我的路由器导航警卫正在检查身份验证状态并在每条路由之前进行路由。

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

  if (requiresAuth && !currentUser) {
    next('login');
  } else if (currentUser
              && !currentUser.emailVerified
              && !allowUnverified
              && to.path !== '/verify') {
    next('verify');
  } else if (!requiresAuth && currentUser) {
    next('dashboard');
  } else {
    next();
  }
});

当您刷新页面(使用有效的身份验证令牌)时,您会遇到路由保护的分支1,stateChanges并调用处理程序以重定向到/ dashboard。登录后刷新,总是会带您到仪表板路线,而不是您当前的路线。

我该如何处理这个案子?为每个auth组件添加一个beforeEnter防护对我来说闻不通Data Fetching Vue Docs

这应该在商店中而不是在根实例上创建的挂钩吗?任何帮助是极大的赞赏。这种模式让我感到难过。

1 个答案:

答案 0 :(得分:3)

快速修复

如果用户存在且不需要身份验证,为什么要将他重定向到另一个页面(仪表板)?

  } else if (!requiresAuth && currentUser) {
    next('dashboard');
  } else {
    next();
  }

你可以让路由继续。

  if (requiresAuth && !currentUser) {
    next('login');
  } else if (requiresAuth && !currentUser.emailVerified && !allowUnverified) {
    next('verify');
  } else {
    next();
  }

您还需要从this.$router.replace('dashboard');回调中删除onAuthStateChanged。请参阅下文以获得更深入的答案。

深度

我会避免在Vue组件中放置身份验证路由逻辑。虽然有一天它可能有意义,但在这种情况下,它可以完全避免。

我喜欢将Vuex商店实例放在一个独立的模块中,以便我可以在其他地方使用它,而不仅限于Vue。

import Vue from 'vue';
import Vuex from 'vuex';
// Configuration is generated with a function, so testing the store is easier
import getConfig from './config';

Vue.use(Vuex);

export default new Vuex.Store(getConfig());

因此可以将身份验证逻辑移至auth.js服务。

import store from './store';
import router from './router';

// other auth related code, you can even export a common API
// to use within your app.
// like this simple wrapper, which hides the fact that you're using firebase
export function getUser() {
  return firebaseApp.auth().currentUser;
}
export default { getUser }

auth.onAuthStateChanged((user) => {
  // store/business logic should be inside the store.
  store.dispatch('user/AUTH_STATE_CHANGED', user);
  // minimal handling of mandatory steps in the login or sign up process
  if (!user) {
     router.push('login');
  } else if (user && !user.emailVerified) {
    router.push('verify');
  }
});

如果用户已正确登录,则没有理由在此处重定向。由于全球导航警卫将完成大部分重定向工作,因此您可以redirect to the current route with router.go() or router.push(router.currentRoute)

事实上,这个导航防护可以在上面提到的auth.js服务中注册。

router.beforeEach((to, from, next) => {
  const currentUser = getUser();
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  const allowUnverified = to.matched.some(record => record.meta.allowUnverified);

  if (requiresAuth && !currentUser) {
    next('login');
  } else if (requiresAuth && !currentUser.emailVerified && !allowUnverified) {
    next('verify');
  } else {
    next();
  }
});

然后,将简单的导航警卫添加到登录后无法访问的路径。

path: '/login',
beforeEnter: (to, from, next) => {
    if (auth.getUser()) {
        next('dashboard');
    } else {
        next();
    }
},

重点是:仅在导航到受限制的网页时强制重定向。

当登录用户刷新页面时,没有理由重定向到/dashboard。如果同一用户尝试导航到登录,则有理由重定向到/dashboard