简体   繁体   中英

Vue.js: How to protect login component from authenticated user

I'm designing an application where auth is implemented using firebase-auth. I have already protected the user component from unauthenticated users. But I now want to protect the login component from authenticated users. I've tried this so far. Here is my router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import {
  fb
} from "@/firebase/init";
import Home from '@/views/Home'

Vue.use(VueRouter)

const routes = [{
    path: '/',
    name: "home",
    component: Home
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('@/components/auth/Login'),
    meta: {
      alreadyAuth: true
    }
  },
  {
    path: '/signup',
    name: 'signup',
    component: () => import('@/components/auth/Signup'),

  },
  {
    path: '/user/:id',
    name: 'user',
    component: () => import('@/components/user/User'),
    meta: {
      requiresAuth: true
    }
  },

]

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

router.beforeEach((to, from, next) => {
  let user = fb.auth().currentUser
  if (to.matched.some(rec => rec.meta.requiresAuth)) {
    if (user) {
      next()
    } else {
      next({
        name: 'login'
      })
    }
  } else if (to.matched.some(rec => rec.meta.alreadyAuth)) {
    if (user) {
      next({
        name: 'user'
      })
    } else {
      next()
    }
  } else {
    next()
  }
})

export default router

And one more problem is that when I'm authenticated and refresh the user component it redirects me back to the login component. Why so?

Thanks in advance

Since I don't know your main.js this is just an assumption, but I think currentUser is undefined . You should log user and check if it is defined on page load. Firebase acts async, so in order to have everything prepared you need to wrap your whole application in a firebase callback.

firebase.auth().onAuthStateChanged(() => {
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app');
});

Otherwise currentUser probably is not yet initialized.

So you want to block logged-in users from hitting your login route, but you also want to stop non-logged in users from hitting certain pages in your Vue app. Pretty standard use case. Here's how I implemented it:

First, my routes have meta tags requiresAuth and forVisitors . If the user is logged in and tries to hit a forVisitors route, I return the user to the homepage ( routeObject.path = '/' in my example below). If the user is not logged in and tries to hit a requiresAuth path, I kick them to /login. I found this approach is pretty flexible for route construction.

My router needs to know what constitutes a logged-in user. Using Firebase's auth module, I can subscribe to onAuthStateChanged and figure out whether the user is logged in from the first emission.

Note, I store the current user in the VueX store ( store.state.userModule.user ), you can ignore that bit if you do not. Also I store the Firebase Auth object in my store as store.state.userModule.auth , so when you see that, it's the same as Firebase auth.

Additionally, you can find more details on why I wrap my onAuthStateChanged subscription in a Promise here: Getting 'Uncaught' after catching error in firebase.auth() with async


const router = new Router({
    /* example of forVisitors path */
    {
        path: '/Login',
        name: 'Login',
        component: Login,
        meta: {
            requiresAuth: false,
            forVisitors: true
        }
    },
    /* example of requiresAuth path */
    {
        path: '/Submit/:mode?/:primary?/:secondary?',
        name: 'Submit',
        component: Submit,
        props: true,
        meta: {
            requiresAuth: true
        }
    }
});

router.beforeEach(async (to, from, next) => {
/* Check for a user in my store, or fallback to Firebase auth() user */
    let currentUser =
        store.state.userModule.user ||
        (await new Promise((resolve) => {
            store.state.userModule.auth().onAuthStateChanged(user => {
                resolve(user);
            });
        }));

    const requiresAuth = to.meta.requiresAuth;
    const forVisitors = to.meta.forVisitors;
    const routeObject = {};

    if (forVisitors && currentUser) {
        routeObject.path = '/';
    } else if (requiresAuth && !currentUser) {
        routeObject.path = '/login';
    }

    next(routeObject);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM