Refactor session handling with SessionUser helper methods:

- Streamline access control logic in middleware files with new `hasToken` and `canAccessGuest` methods.
- Rework `DefaultPage` to dynamically redirect users based on hierarchical access levels.
- Improve guest user redirection by integrating query-based redirect paths.
- Enhance maintainability and reduce reliance on `localStorage` for session validation.
This commit is contained in:
Jeppe Bundgaard
2025-07-24 09:49:12 +02:00
parent d66c237106
commit 26338c4f71
7 changed files with 135 additions and 19 deletions
+1
View File
@@ -24,6 +24,7 @@ const login = async () => {
});
// Save the token in the local storage
localStorage.setItem('token', response.data.data.token);
// Reload the router to update the session
window.location.reload();
} catch (e) {
parseError(e, 'auth');
@@ -188,6 +188,12 @@ export const SessionUser = {
// If the url is localhost, we can assume that the user is a developer
return window.location.hostname === "localhost";
},
canAccessGuest: () => {
return true; // All users can access guest features
},
hasToken: () => {
return SessionUser.token.value !== null;
},
/** Shortcuts for the user's group */
superUser: SuperUserObject,
adminUser: AdminUserObject,
+8 -2
View File
@@ -2,10 +2,16 @@
* @description Middleware to check if user is admin
*/
import store from '@/store/user.vue';
import { SessionUser } from "@/components/session/token/SessionUser.vue";
export default function adminMiddleware({ next, router }) {
if (!localStorage.getItem('token')) {
return router.push({ name: 'login' });
if (!SessionUser.hasToken()) {
return router.push({
// Redirect to login page
name: 'login',
// Set redirect path to current route
query: { redirect: window.location.href }
});
}
return next();
+10 -3
View File
@@ -2,10 +2,17 @@
* Auth Middleware
*/
import store from '@/store/user.vue';
import { SessionUser } from "@/components/session/token/SessionUser.vue";
export default function authMiddleware({ next, router }) {
if (!localStorage.getItem('token')) {
return router.push({ name: 'login' });
}
if (!SessionUser.hasToken()) {
return router.push({
// Redirect to login page
name: 'login',
// Set redirect path to current route
query: { redirect: window.location.href }
});
}
return next();
}
+20 -2
View File
@@ -2,8 +2,26 @@
* Middleware responsible for redirecting authenticated users to the dashboard
*/
import store from '@/store/user.vue';
import { SessionUser } from "@/components/session/token/SessionUser.vue";
export default function guestMiddleware({ next, router }) {
if (localStorage.getItem('token'))
return router.push({ name: 'dashboard' });
// Check if the user is authenticated
if (SessionUser.hasToken()) {
// Check if a redirect path is set in the query "redirect" parameter
const urlParams = new URLSearchParams(window.location.search);
const redirectPath = urlParams.get('redirect') || undefined;
const redirectUrl = redirectPath ? new URL(redirectPath, window.location.origin) : undefined;
// Redirect to the specified path or default to '/dashboard'
if (redirectUrl && redirectUrl.pathname) {
console.log('Redirecting to:', redirectUrl.pathname, 'with query:', redirectUrl.search, 'and hash:', redirectUrl.hash, 'from guestMiddleware');
// Clear the redirect query parameter
urlParams.delete('redirect');
// Update the URL without the redirect query parameter
window.history.replaceState({}, '', `${redirectUrl.pathname}${urlParams.toString() ? '?' + urlParams.toString() : ''}${redirectUrl.hash}`);
window.location.reload();
} else {
window.location.href = '/';
}
}
return next();
}
+9 -3
View File
@@ -2,11 +2,17 @@
* @description Middleware to check if the user is a superuser
*/
import store from '@/store/user.vue';
import { SessionUser } from "@/components/session/token/SessionUser.vue";
export default function superUserMiddleware({ next, router }) {
if (!localStorage.getItem('token')) {
return router.push({ name: 'login' });
}
if (!SessionUser.hasToken()) {
return router.push({
// Redirect to login page
name: 'login',
// Set redirect path to current route
query: { redirect: window.location.href }
});
}
return next();
}
+81 -9
View File
@@ -3,24 +3,96 @@
import PageTitle from "@/components/global/PageTitle.vue";
import PageLoader from "@/components/global/PageLoader.vue";
import { ref } from 'vue'
import {computed, onMounted, ref, watch} from 'vue'
import { useRouter } from "vue-router";
const router = useRouter();
import { SessionUser } from "@/components/session/token/SessionUser.vue";
// If the user has the superuser permission, redirect to the superuser dashboard
if (SessionUser.canAccessSuperUser()) {
router.push({ name: 'superuser' });
const hiarchyAccessLevels = {
superuser: {
name: 'superuser',
level: 3,
access: computed(() => SessionUser.canAccessSuperUser()),
route: 'superuser'
},
admin: {
name: 'admin',
level: 2,
access: computed(() => SessionUser.canAccessAdmin()),
route: 'admin'
},
user: {
name: 'user',
level: 1,
access: computed(() => SessionUser.canAccessUser()),
route: 'dashboard'
},
guest: {
name: 'guest',
level: 0, access: computed(() => SessionUser.canAccessGuest()),
route: 'login'
}
};
const checkSessionHighestAccessLevel = () => {
if (!SessionUser.isInitiated()) {
// If the session is not initiated, we cannot determine the access level
return undefined;
}
let highestAccessLevel = null;
// Iterate through the access levels in descending order of hierarchy
for (const accessLevel of Object.values(hiarchyAccessLevels).sort((a, b) => b.level - a.level)) {
if (accessLevel.access.value) {
// If the user has access to this level, set it as the highest access level
highestAccessLevel = accessLevel;
break; // Exit the loop once the highest access level is found
}
}
if (highestAccessLevel) {
// If the highest access level is found, return it
return highestAccessLevel;
}
// If no access level is found, return null
return null;
}
// If the user has the admin permission, redirect to the department dashboard
if (SessionUser.canAccessAdmin()) {
router.push({ name: 'admin' });
const attemptRedirect = () => {
const highestAccessLevel = checkSessionHighestAccessLevel();
if (highestAccessLevel) {
// Redirect to the route associated with the highest access level
router.push({ name: highestAccessLevel.route });
} else if (!SessionUser.hasToken()) {
// If no access level is found and the user does not have a token, redirect to the login page
router.push({ name: 'login' });
} else {
// If the session is not initiated, it might just be loading, so we can wait for the session to be initiated
}
}
// Redirect to dashboard (user is already logged in, or will be redirected to login page)
router.push({ name: 'dashboard' });
// Attempt to redirect when the component is mounted
onMounted(() => {
attemptRedirect();
})
// Watch for changes in the session user initiation status
watch(() => SessionUser.initiated.value, (newValue) => {
if (newValue) {
console.log('Session initiated, attempting redirect');
// If the session is initiated, attempt to redirect
attemptRedirect();
}
});
// Watch for changes in the permissions of the session user
watch(() => SessionUser.permissions.value, (newValue) => {
if (newValue) {
console.log('Permissions changed, attempting redirect');
// If the session is initiated, attempt to redirect
attemptRedirect();
}
});
</script>
<template>