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.