router.js
./src/router.js
import Vue from 'vue' import Router from 'vue-router' import firebase from 'firebase' const routerOptions = [ { path: '/', component: 'Landing' }, { path: '/signin', component: 'Signin' }, { path: '/signup', component: 'Signup' }, { path: '/home', component: 'Home', meta: { requiresAuth: true } }, { path: '*', component: 'NotFound' } ] const routes = routerOptions.map(route => { return { ...route, component: () => import(`@/components/${route.component}.vue`) } }) Vue.use(Router) const router = new Router({ mode: 'history', routes }) router.beforeEach((to, from, next) => { const requiresAuth = to.matched.some(record => record.meta.requiresAuth) const isAuthenticated = firebase.auth().currentUser if (requiresAuth && !isAuthenticated) { next('/signin') } else { next() } }) export default router
Importaciones
Se importan:
import Vue from 'vue' import Router from 'vue-router' import firebase from 'firebase'
las librerías:
- vue
- vue-router
- firebase
Rutas
Definimos las rutas:
const routerOptions = [ { path: '/', component: 'Landing' }, { path: '/signin', component: 'Signin' }, { path: '/signup', component: 'Signup' }, { path: '/home', component: 'Home', meta: { requiresAuth: true } }, { path: '*', component: 'NotFound' } ] const routes = routerOptions.map(route => { return { ...route, component: () => import(`@/components/${route.component}.vue`) } })
en donde routerOptions
es una lista de objetos en los que se indica la ruta y el componente asociado (por nombre). Como vemos, para home
, se requiere que el usuario esté autentificado. Puede ser deseable redirigir a los usuarios que quieran acceder a rutas protegidas.
Vemos que se define la función component
, que es la que importa el fichero .vue
.
Usar el router
Indicamos a Vue que use Router. Por otro lado, se crea una instancia configurada en modo history
:
Vue.use(Router) const router = new Router({ mode: 'history', routes })
Rutas protegidas
Vimos con anterioridad que queríamos proteger la siguiente ruta:
{ path: '/home', component: 'Home', meta: { requiresAuth: true } },
Para posibilitarlo, definimos la siguiente función (guard function) que se ejecutará antes de que accedamos a una ruta:
router.beforeEach((to, from, next) => { const requiresAuth = to.matched.some(record => record.meta.requiresAuth) const isAuthenticated = firebase.auth().currentUser if (requiresAuth && !isAuthenticated) { next('/signin') } else { next() } }) export default router
Como vemos, la siguiente línea comprueva si la ruta a la que vamos tiene un valor meta.requiresAuth=true
:
const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
La siguiente línea devuelve el usuario actual:
const isAuthenticated = firebase.auth().currentUser
El siguiente código nos envía a la página /signin
cuando la ruta requiera autorización y no estemos logeados. Nos llevará a la página objetivo en caso contrario.
Finalmente se exporta la instacia router
.
Sin embargo esto no funcionará:
Si entramos en la aplicación y hacemos "sign in", nos redirigirá a /home
. Si volvemos a cargar la página, nos enviaría a /signin
. ¿Por qué? Porque cuando beforeEach
ejecuta firebase.auth().currentUser
obtenemos null
. Esto ocurre porque durante la ejecución de beforeEach
, nuestro Firebase onAuthStateChanged
no ha resuelto el estado del usario todavía.
La solución consiste en ejecutar la función beforeEach
después de que onAuthStateChanged
haya resuelto el usuario.