add: guard in router

This commit is contained in:
Alexandro Uc Santos
2024-12-14 17:46:38 -06:00
parent e24f96c061
commit fa56d25258
9 changed files with 148 additions and 37 deletions

View File

@@ -3,9 +3,18 @@
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../stores/auth';
import Swal from 'sweetalert2'; import Swal from 'sweetalert2';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useCompanyStore } from '../stores/company';
import { useVehiclesStore } from '../stores/vehicles';
import { useLoadsStore } from '../stores/loads';
import { useNotificationsStore } from '../stores/notifications';
const route = useRoute(); const route = useRoute();
const auth = useAuthStore(); const auth = useAuthStore();
const company = useCompanyStore();
const vehicles = useVehiclesStore();
const loads = useLoadsStore();
const noty = useNotificationsStore();
const router = useRouter();
const { t } = useI18n() const { t } = useI18n()
const handleLogout = () => { const handleLogout = () => {
@@ -20,6 +29,11 @@
}).then(async(result) => { }).then(async(result) => {
if(result.isConfirmed) { if(result.isConfirmed) {
auth.logout(); auth.logout();
company.clear();
vehicles.clear();
loads.clear();
noty.clear();
router.push({name: 'login'});
} }
}); });
} }

View File

@@ -6,10 +6,13 @@ import App from './App.vue'
import router from './router' import router from './router'
import i18n from './i18n/i18n' import i18n from './i18n/i18n'
const pinia = createPinia();
const app = createApp(App) const app = createApp(App)
app.use(createPinia())
app.use(router) app.use(router)
app.use(pinia)
app.use(i18n) app.use(i18n)
app.mount('#app') app.mount('#app')

View File

@@ -1,6 +1,7 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import AuthLayout from '../layouts/AuthLayout.vue' import AuthLayout from '../layouts/AuthLayout.vue'
import PublicLayout from '../layouts/PublicLayout.vue' import PublicLayout from '../layouts/PublicLayout.vue'
import { useAuthStore } from '../stores/auth';
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@@ -30,6 +31,11 @@ const router = createRouter({
name: 'register-company', name: 'register-company',
component: () => import('../views/CompleteRegisterView.vue') component: () => import('../views/CompleteRegisterView.vue')
}, },
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('../views/LoginView.vue'),
}
] ]
}, },
{ {
@@ -68,88 +74,121 @@ const router = createRouter({
path: '/dashboard', path: '/dashboard',
name: 'dashboard', name: 'dashboard',
component: () => import('../layouts/AdminLayout.vue'), component: () => import('../layouts/AdminLayout.vue'),
meta: { requiresAuth: true }, meta: {
requiresAuth: true,
roles: ['manager', 'staff', 'owner']
},
children: [ children: [
{ {
path: 'inicio', path: 'inicio',
name: 'home', name: 'home',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/HomeView.vue'), component: () => import('../views/HomeView.vue'),
}, },
{ {
path: 'empresa', path: 'empresa',
name: 'company', name: 'company',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/MyCompanyView.vue'), component: () => import('../views/MyCompanyView.vue'),
}, },
{ {
path: 'profile', path: 'profile',
name: 'profile', name: 'profile',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/EditProfileView.vue'), component: () => import('../views/EditProfileView.vue'),
}, },
{ {
path: 'empresa/:id', path: 'empresa/:id',
name: 'public-users', name: 'public-users',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/PublicUsersCompanyView.vue'), component: () => import('../views/PublicUsersCompanyView.vue'),
}, },
{ {
path: 'ubicaciones', path: 'ubicaciones',
name: 'locations', name: 'locations',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/LocationsView.vue'), component: () => import('../views/LocationsView.vue'),
}, },
{ {
path: 'ofertas', path: 'ofertas',
name: 'published-trucks', name: 'published-trucks',
meta: { permissions: ['role_carrier'] },
component: () => import('../views/TrucksPublishedView.vue'), component: () => import('../views/TrucksPublishedView.vue'),
}, },
{ {
path: 'usuarios', path: 'usuarios',
name: 'users', name: 'users',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/UsersView.vue'), component: () => import('../views/UsersView.vue'),
}, },
{ {
path: 'calculadora', path: 'calculadora',
name: 'calculator', name: 'calculator',
meta: { permissions: ['role_carrier'] },
component: () => import('../views/CalculatorView.vue'), component: () => import('../views/CalculatorView.vue'),
}, },
{ {
path: 'reportes', path: 'reportes',
name: 'reports', name: 'reports',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/ReportsView.vue'), component: () => import('../views/ReportsView.vue'),
}, },
{ {
path: 'calendario', path: 'calendario',
name: 'calendar', name: 'calendar',
meta: {
permissions: ['role_shipper', 'role_carrier'],
roles: ['staff', 'manager', 'owner', 'store']
},
component: () => import('../views/CalendarView.vue'), component: () => import('../views/CalendarView.vue'),
}, },
{ {
path: 'cargas', path: 'cargas',
meta: { permissions: ['role_shipper'] },
name: 'published-loads', name: 'published-loads',
component: () => import('../views/LoadsPublishedView.vue'), component: () => import('../views/LoadsPublishedView.vue'),
}, },
{ {
path: 'vehiculos', path: 'vehiculos',
name: 'vehicles', name: 'vehicles',
meta: { permissions: ['role_carrier'] },
component: () => import('../views/VehiclesView.vue'), component: () => import('../views/VehiclesView.vue'),
}, },
{ {
path: 'transportistas', path: 'transportistas',
name: 'carriers', name: 'carriers',
meta: { permissions: ['role_shipper'] },
component: () => import('../views/CarriersView.vue'), component: () => import('../views/CarriersView.vue'),
}, },
{ {
path: 'embarcadores', path: 'embarcadores',
name: 'shippers', name: 'shippers',
meta: { permissions: ['role_carrier'] },
component: () => import('../views/ShippersView.vue'), component: () => import('../views/ShippersView.vue'),
}, },
{ {
path: 'buscar-cargas', path: 'buscar-cargas',
name: 'search-loads', name: 'search-loads',
meta: { permissions: ['role_carrier'] },
component: () => import('../views/SearchLoadsView.vue'), component: () => import('../views/SearchLoadsView.vue'),
}, },
{ {
path: 'buscar-vehiclulos', path: 'buscar-vehiculos',
name: 'search-vehicles', name: 'search-vehicles',
meta: { permissions: ['role_shipper'] },
component: () => import('../views/SearchVehiclesView.vue'), component: () => import('../views/SearchVehiclesView.vue'),
}, },
{
path: '403',
name: '403',
meta: { permissions: ['role_shipper', 'role_carrier'] },
component: () => import('../views/NotFoundView.vue'),
},
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('../views/HomeView.vue'),
}
] ]
} }
] ]
@@ -158,16 +197,63 @@ const router = createRouter({
router.beforeEach( async(to, from, next) => { router.beforeEach( async(to, from, next) => {
const requiresAuth = to.matched.some(url => url.meta.requiresAuth) const requiresAuth = to.matched.some(url => url.meta.requiresAuth)
if(requiresAuth === true) { if(requiresAuth === true) {
const auth = useAuthStore()
const session = localStorage.getItem('session'); const session = localStorage.getItem('session');
//Comprobamos si el usuario esta authenticado const permissions = to.meta.permissions;
const roles = to.meta.roles;
if(session) { if(session) {
await auth.checkSession()
const permissionUser = auth?.user?.permissions;
const role = auth?.user?.job_role;
if (!permissionUser) {
return next({name: 'login'}); // Redirige al login si no está autenticado
}
if (permissions && !permissions.includes(permissionUser)) {
if(role === 'store') { /// Check if user is store
return next({name: 'calendar'});
} else {
return next({name: 'home'});
}
}
if(roles && !roles.includes(role)) {
return next({name: 'calendar'});
}
next(); next();
} else { } else {
next({name: 'login'}) return next({name: 'login'})
} }
} else { } else {
next(); next();
} }
}); });
// router.beforeEach( async(to, from, next) => {
// const requiresAuth = to.matched.some(url => url.meta.requiresAuth)
// if(requiresAuth === true) {
// const session = localStorage.getItem('session');
// const role = localStorage.getItem('user');
// const permissions = to.meta.permissions;
// const auth = useAuthStore()
// //Comprobamos si el usuario esta authenticado
// if(session) {
// if (!role) {
// return next({name: 'login'}); // Redirige al login si no está autenticado
// }
// if (permissions && !permissions.includes(role)) {
// return next({name: 'home'}); // Redirige a una página de acceso denegado si no tiene permisos
// }
// next();
// } else {
// return next({name: 'login'})
// }
// } else {
// next();
// }
// });
export default router export default router

View File

@@ -3,9 +3,7 @@ import { ref, onMounted } from "vue";
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { renewToken } from '../services/auth'; import { renewToken } from '../services/auth';
import {useNotificationsStore} from './notifications'; import {useNotificationsStore} from './notifications';
import {useCompanyStore} from './company';
import { useLoadsStore } from "./loads"; import { useLoadsStore } from "./loads";
import { useVehiclesStore } from "./vehicles";
import { updateMyUserProfile } from "../services/company"; import { updateMyUserProfile } from "../services/company";
export const useAuthStore = defineStore('auth', () => { export const useAuthStore = defineStore('auth', () => {
@@ -13,16 +11,14 @@ export const useAuthStore = defineStore('auth', () => {
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const noty = useNotificationsStore(); const noty = useNotificationsStore();
const company = useCompanyStore();
const loadStore = useLoadsStore(); const loadStore = useLoadsStore();
const vehiclesStore = useVehiclesStore();
const notyStore = useNotificationsStore();
const sesion = ref('') const sesion = ref('')
const checking = ref(false); const checking = ref(false);
const authStatus = ref('checking'); const authStatus = ref('checking');
const token = ref('') const token = ref('')
const lang = ref('es'); const lang = ref('es');
const user = ref(null); const user = ref(null);
const isAuthenticated = ref(false);
const publicNames = [ const publicNames = [
'terms-conditions', 'terms-conditions',
'notice-privacy', 'notice-privacy',
@@ -34,15 +30,10 @@ export const useAuthStore = defineStore('auth', () => {
'register-company', 'register-company',
] ]
onMounted( async() => {
checkSession();
});
const checkSession = async() => { const checkSession = async() => {
const session = localStorage.getItem('session'); const session = localStorage.getItem('session');
authStatus.value = 'checking'; authStatus.value = 'checking';
if(session && !publicNames.includes(route.name)) { if((session && !publicNames.includes(route.name)) && isAuthenticated.value === false && checking.value === false) {
checking.value = true; checking.value = true;
const resp = await renewToken(); const resp = await renewToken();
if(resp.msg === 'success') { if(resp.msg === 'success') {
@@ -53,22 +44,24 @@ export const useAuthStore = defineStore('auth', () => {
localStorage.setItem('access', resp.data.accessToken); localStorage.setItem('access', resp.data.accessToken);
localStorage.setItem('id', resp.data.user.company._id); localStorage.setItem('id', resp.data.user.company._id);
checking.value = false; checking.value = false;
isAuthenticated.value = true;
} else { } else {
noty.show = true; noty.show = true;
noty.text = 'Sesión ha expirado, ingresa nuevamente'; noty.text = 'Sesión ha expirado, ingresa nuevamente';
noty.error = true; noty.error = true;
checking.value = false; checking.value = false;
isAuthenticated.value = false;
router.push({name: 'login'}); router.push({name: 'login'});
} }
} }
authStatus.value = 'completed'; authStatus.value = 'completed';
} }
const authenticationPromise = new Promise((resolve) => { // const authenticationPromise = new Promise((resolve) => {
onMounted(() => { // onMounted(() => {
resolve('success'); // resolve('success');
}); // });
}); // });
const updateProfile = async(data) => { const updateProfile = async(data) => {
const response = await updateMyUserProfile(data); const response = await updateMyUserProfile(data);
@@ -90,17 +83,7 @@ export const useAuthStore = defineStore('auth', () => {
user.value = null; user.value = null;
checking.value = false; checking.value = false;
authStatus.value = 'checking' authStatus.value = 'checking'
notyStore.notifications = [];
notyStore.newNoty = false;
notyStore.show = false;
notyStore.openNotifications = false;
notyStore.toggleProfile = false;
company.clear();
loadStore.clear(); loadStore.clear();
vehiclesStore.clear();
router.push({name: 'login'});
} }
return { return {
@@ -111,8 +94,9 @@ export const useAuthStore = defineStore('auth', () => {
checking, checking,
authStatus, authStatus,
checkSession, checkSession,
authenticationPromise, // authenticationPromise,
updateProfile, updateProfile,
lang lang,
isAuthenticated
} }
}); });

View File

@@ -34,6 +34,15 @@ export const useNotificationsStore = defineStore('notifications', () => {
return notifications.value = notifications.value.filter(noty => noty._id !== id); return notifications.value = notifications.value.filter(noty => noty._id !== id);
} }
const clear = () => {
notifications.value = [];
newNoty.value = false;
show.value = false;
openNotifications.value = false;
toggleProfile.value = false;
}
return { return {
text, text,
@@ -45,6 +54,7 @@ export const useNotificationsStore = defineStore('notifications', () => {
removeNoty, removeNoty,
toggleProfile, toggleProfile,
openNotifications, openNotifications,
toggleNotifications toggleNotifications,
clear
} }
}); });

View File

@@ -98,7 +98,7 @@
localStorage.setItem('id', result.data._id); localStorage.setItem('id', result.data._id);
localStorage.setItem('session', auth.sesion); localStorage.setItem('session', auth.sesion);
// localStorage.setItem('access', auth.token); localStorage.setItem('access', auth.accessToken);
const userData = { const userData = {
"first_name" : user.name, "first_name" : user.name,
@@ -109,6 +109,7 @@
let respUser = await updateMyUserProfile( userData ); let respUser = await updateMyUserProfile( userData );
if(respUser.msg === 'success') { if(respUser.msg === 'success') {
auth.user = respUser.data; auth.user = respUser.data;
auth.isAuthenticated = true;
} else { } else {
auth.user = userData; auth.user = userData;
} }

View File

@@ -48,6 +48,7 @@
sesion: resp.data.session_token, sesion: resp.data.session_token,
token: resp.data.accessToken, token: resp.data.accessToken,
user: resp.data.user, user: resp.data.user,
isAuthenticated: true
}) })
} else { // Completar registro } else { // Completar registro
auth.$patch({ auth.$patch({

View File

@@ -27,7 +27,6 @@
}) })
const getInitialData = async() => { const getInitialData = async() => {
await auth.authenticationPromise;
await company.getCompanyData(); await company.getCompanyData();
} }

View File

@@ -0,0 +1,13 @@
<template>
<div>
<h1>No encontrada</h1>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>