Search code examples
vue.jsvue-routervuejs3vue-router4

how to auth the user in vue 3?


I am having some issue login the user in my app using vue 3 (vue-cli) and vue-router 4

This is the router.js

import { createRouter, createWebHistory } from 'vue-router';

import store from '../store';

import AuthLayout from "../layouts/AuthLayout";
import DashboardLayout from "../layouts/DashboardLayout";
import PageNotFound from "../views/errors/PageNotFound";

import Login from "../views/auth/Login";
import Logout from "../views/auth/Logout"
import Dashboard from "../views/dashboard/Dashboard";

let routes = [
  {
    path: '/',
    redirect: 'dashboard',
    component: DashboardLayout,
    children: [
      {
        path: '/',
        component: Dashboard,
        name: 'dashboard',
        meta: {
          requiresAuth: true
        }
      },
      {
        path: '/logout',
        component: Logout,
        name: 'logout',
        meta: {
          requiresAuth: true
        }
      },
      {
        path: '/:pathMatch(.*)*',
        component: PageNotFound,
        name: 'page-not-found',
        meta: {
          requiresAuth: true
        }
      }
    ]
  },
  {
    path: '/',
    redirect: 'login',
    component: AuthLayout,
    children: [
      {
        path: '/login',
        component: Login,
        name: 'login',
        meta: {
          requiresVisitor: true
        }
      },
    ]
  }
];

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes: routes,
  linkExactActiveClass: 'active'
});

// eslint-disable-next-line no-unused-vars
router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !store.state.authenticated) {
    return {
      name: 'login',
    }
  }
})

export default router;

I am importing the store in routes to access the state authenticated. When the server auth the user then authenticated = true.

The authenticated (state from vuex) ... it is true now... but it stays at login form. If I force to go in / (dashboard) it return again to login.

The user is logged in.

Anyone have an idea what I am missing in routes.js ???

***** UPDATE *****

Login component

export default {
  name: "Login.vue",
  setup() {
    const axios = inject('$axios')
    const store = useStore()
    const authenticated = computed(() => store.state.authenticated)

    const auth = ref( {
      email: '',
      password: ''
    })

    const authUser = () => {
      axios.get('/api/user').then(response => {
        store.commit('setAuthenticated',true);
        store.commit('setUser', response.data)
      })
    }

    const handleLogin = () => {
      // eslint-disable-next-line no-unused-vars
      axios.post('/login', auth.value).then(response => {
        authUser()
      }).catch(error => {
        console.log(error)       
      })
    }

    onMounted(() => {
      // eslint-disable-next-line no-unused-vars
      axios.get('/sanctum/csrf-cookie').then(response => {
        authUser()
      })
    })

    return { auth, handleLogin, authenticated }
  }
}

Solution

  • The issue, I believe, is that the authentication state is not persistent. That means, that the data is gone if you redirect (using a manual url change) or refresh.

    You can add persistence by

    const state = {
      authenticated: localStorage.getItem('authenticated')==='true'; // get authentication from local storage
    }
    const store = createStore({
      state: state,
      mutations: {
        setAuthenticated(state, payload) {
          state.authenticated = payload;
          localStorage.setItem('authenticated', payload); // sill store 'true' in local storage
        }
      }
    })
    

    This will store the authenticated state in your localStorage. It populates the store state.authenticated value on instantiation, and updates on change.

    There's some other considerations, such as redirecting

        const authUser = () => {
          axios.get('/api/user').then(response => {
            store.commit('setAuthenticated',true);
            store.commit('setUser', response.data);
            router.push('/'); // <= will redirect after the values are set
          })
        }