From 0b58579258f0c1b8f1f84f925a7dbd0511ec21db Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 29 Apr 2026 18:52:16 +0200 Subject: [PATCH] Refactor authentication and token management: Update authController.js to use environment variable for JWT expiration. Enhance axios.js and store/index.js for improved token usability checks and cleanup on logout, ensuring a more robust authentication flow. --- controllers/authController.js | 6 ++++- src/axios.js | 46 +++++++++++++++++++++++++++++------ src/store/index.js | 27 +++++++++++++++++--- 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/controllers/authController.js b/controllers/authController.js index cd47d02..3ed1592 100644 --- a/controllers/authController.js +++ b/controllers/authController.js @@ -82,7 +82,11 @@ exports.login = async (req, res) => { if (!user.active) { return res.status(403).json({ message: 'Benutzerkonto ist nicht aktiv' }); } - const token = jwt.sign({ id: user.id, name: user.name, email: user.email }, 'zTxVgptmPl9!_dr%xxx9999(dd)', { expiresIn: '1h' }); + const token = jwt.sign( + { id: user.id, name: user.name, email: user.email }, + 'zTxVgptmPl9!_dr%xxx9999(dd)', + { expiresIn: process.env.JWT_EXPIRES_IN || '12h' } + ); return res.status(200).json({ message: 'Login erfolgreich', token, 'user': user }); } catch (error) { return res.status(500).json({ message: 'Ein Fehler ist aufgetreten' }); diff --git a/src/axios.js b/src/axios.js index 47a6754..9ff36df 100644 --- a/src/axios.js +++ b/src/axios.js @@ -1,6 +1,4 @@ import axios from 'axios'; -import store from './store'; -import router from './router'; // Einheitliche Basis-URL: // - immer relativ zur aktuellen Origin @@ -8,11 +6,45 @@ import router from './router'; axios.defaults.baseURL = '/api'; console.log('Axios baseURL:', axios.defaults.baseURL); +function clearStoredLogin() { + localStorage.removeItem('isLoggedIn'); + localStorage.removeItem('user'); + localStorage.removeItem('token'); + delete axios.defaults.headers.common.Authorization; +} + +function getTokenPayload(token) { + try { + const payload = token.split('.')[1]; + const normalized = payload.replace(/-/g, '+').replace(/_/g, '/'); + const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, '='); + return JSON.parse(atob(padded)); + } catch (error) { + return null; + } +} + +function isTokenUsable(token) { + if (!token || token === 'undefined' || token === 'null') { + return false; + } + const payload = getTokenPayload(token); + if (!payload || !payload.exp) { + return true; + } + return payload.exp * 1000 > Date.now(); +} + axios.interceptors.request.use( config => { - const token = store.state.token || localStorage.getItem('token'); + const token = localStorage.getItem('token'); if (token) { - config.headers.Authorization = `Bearer ${token}`; + if (isTokenUsable(token)) { + config.headers.Authorization = `Bearer ${token}`; + } else { + clearStoredLogin(); + delete config.headers.Authorization; + } } return config; }, @@ -31,9 +63,9 @@ axios.interceptors.response.use( const isLogoutRequest = requestUrl.includes('/auth/logout'); if (error.response && error.response.status === 401 && !isLoginRequest && !isLogoutRequest) { - store.commit('logout'); - if (router.currentRoute.value.path !== '/auth/login') { - router.replace('/auth/login'); + clearStoredLogin(); + if (window.location.pathname !== '/auth/login') { + window.location.replace('/auth/login'); } } return Promise.reject(error); diff --git a/src/store/index.js b/src/store/index.js index 598388e..a33229d 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -8,10 +8,31 @@ const storedToken = ? rawStoredToken : ''; -if (!storedToken) { +function getTokenPayload(token) { + try { + const payload = token.split('.')[1]; + const normalized = payload.replace(/-/g, '+').replace(/_/g, '/'); + const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, '='); + return JSON.parse(atob(padded)); + } catch (e) { + return null; + } +} + +function isTokenUsable(token) { + if (!token) return false; + const payload = getTokenPayload(token); + if (!payload || !payload.exp) return true; + return payload.exp * 1000 > Date.now(); +} + +const usableStoredToken = isTokenUsable(storedToken) ? storedToken : ''; + +if (!usableStoredToken) { // Altlasten aus früheren Login-Bugs bereinigen localStorage.removeItem('isLoggedIn'); localStorage.removeItem('token'); + localStorage.removeItem('user'); } let user = []; @@ -23,9 +44,9 @@ try { export default createStore({ state: { - isLoggedIn: localStorage.getItem('isLoggedIn') === 'true' && !!storedToken, + isLoggedIn: localStorage.getItem('isLoggedIn') === 'true' && !!usableStoredToken, user: user, - token: storedToken, + token: usableStoredToken, menuData: [], /** gesetzt, wenn /menu-data fehlschlägt (z. B. DB weg) — nicht mit „Seite nicht gefunden“ verwechseln */ menuLoadError: null,