254 lines
8.6 KiB
JavaScript
254 lines
8.6 KiB
JavaScript
import { createAuth } from '@websanova/vue-auth';
|
|
import driverAuthBearer from '@websanova/vue-auth/dist/drivers/auth/bearer.esm.js';
|
|
import driverHttpAxios from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js';
|
|
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js';
|
|
import axios from 'axios';
|
|
import { createPinia } from 'pinia';
|
|
import { createApp } from 'vue';
|
|
import App from './App.vue';
|
|
import router from './router';
|
|
import { AuthService } from './service/AuthService.js';
|
|
import { TokenRefreshManager } from './service/TokenRefreshManager.js';
|
|
|
|
import '@/assets/styles.scss';
|
|
import '@/assets/tailwind.css';
|
|
import BlockViewer from '@/components/BlockViewer.vue';
|
|
import { definePreset } from '@primevue/themes';
|
|
import Nora from '@primevue/themes/nora';
|
|
import { config } from 'md-editor-v3';
|
|
import PrimeVue from 'primevue/config';
|
|
import ConfirmationService from 'primevue/confirmationservice';
|
|
import ToastService from 'primevue/toastservice';
|
|
import { LoadingStore } from './stores/LoadingStore.js';
|
|
|
|
// Declare variables that will be used globally
|
|
let authInstance = null;
|
|
let tokenRefreshManager = null;
|
|
|
|
config({
|
|
editorConfig: {
|
|
renderDelay: 0,
|
|
zIndex: 200000000
|
|
}
|
|
});
|
|
var auth = createAuth({
|
|
plugins: {
|
|
http: axios,
|
|
router: router
|
|
},
|
|
drivers: {
|
|
http: driverHttpAxios,
|
|
auth: driverAuthBearer,
|
|
router: driverRouterVueRouter
|
|
},
|
|
options: {
|
|
notFoundRedirect: '/',
|
|
authRedirect: '/',
|
|
authRedirect: true, // niente redirect automatici
|
|
notFoundRedirect: false,
|
|
loginData: { url: '/api/auth/login', method: 'POST', redirect: '/home' },
|
|
logoutData: { url: '/api/auth/logout', redirect: '/auth/login' },
|
|
fetchData: { url: '/api/auth/fetch-user', method: 'GET', enabled: false },
|
|
refreshData: { url: '/api/auth/refresh-token', method: 'GET', enabled: true }
|
|
}
|
|
});
|
|
|
|
//axios.defaults.baseURL = import.meta.env.VITE_BACKEND_URL;
|
|
axios.defaults.baseURL = 'http://localhost:8081';
|
|
|
|
console.log(import.meta.env.VITE_BACKEND_URL);
|
|
|
|
const app = createApp(App);
|
|
const pinia = createPinia();
|
|
const preset = definePreset(Nora, {
|
|
semantic: {
|
|
primary: {
|
|
50: '{violet.50}',
|
|
100: '{violet.100}',
|
|
200: '{violet.200}',
|
|
300: '{violet.300}',
|
|
400: '{violet.400}',
|
|
500: '{violet.500}',
|
|
600: '{violet.600}',
|
|
700: '{violet.700}',
|
|
800: '{violet.800}',
|
|
900: '{violet.900}',
|
|
950: '{violet.950}'
|
|
},
|
|
colorScheme: {
|
|
light: {
|
|
surface: {
|
|
0: '#f3f3f3',
|
|
50: '{viva.50}',
|
|
100: '{viva.100}',
|
|
200: '{viva.200}',
|
|
300: '{viva.300}',
|
|
400: '{viva.400}',
|
|
500: '{viva.500}',
|
|
600: '{viva.600}',
|
|
700: '{viva.700}',
|
|
800: '{viva.800}',
|
|
900: '{viva.900}',
|
|
950: '{viva.950}'
|
|
},
|
|
formField: {
|
|
hoverBorderColor: '{primary.color}',
|
|
borderColor: '{primary.color}'
|
|
}
|
|
},
|
|
dark: {
|
|
surface: {
|
|
0: '#ffffff',
|
|
50: '{slate.50}',
|
|
100: '{slate.100}',
|
|
200: '{slate.200}',
|
|
300: '{slate.300}',
|
|
400: '{slate.400}',
|
|
500: '{slate.500}',
|
|
600: '{slate.600}',
|
|
700: '{slate.700}',
|
|
800: '{slate.800}',
|
|
900: '{slate.900}',
|
|
950: '{slate.950}'
|
|
},
|
|
formField: {
|
|
hoverBorderColor: '{primary.color}',
|
|
borderColor: '{primary.color}'
|
|
}
|
|
}
|
|
},
|
|
focusRing: {
|
|
width: '2px',
|
|
color: '{primary.color}',
|
|
offset: '1px'
|
|
}
|
|
}
|
|
});
|
|
|
|
app.use(pinia);
|
|
app.use(router);
|
|
|
|
app.use(PrimeVue, {
|
|
theme: {
|
|
preset: preset,
|
|
options: {
|
|
prefix: 'p',
|
|
darkModeSelector: '.app-dark',
|
|
cssLayer: false
|
|
}
|
|
}
|
|
});
|
|
app.use(ToastService);
|
|
app.use(ConfirmationService);
|
|
app.use(auth);
|
|
|
|
app.component('BlockViewer', BlockViewer);
|
|
|
|
app.mount('#app');
|
|
|
|
// Store auth instance for interceptor and token refresh manager after app is mounted
|
|
authInstance = app.config.globalProperties.$auth;
|
|
tokenRefreshManager = new TokenRefreshManager(authInstance);
|
|
|
|
// Start token refresh timer when user is authenticated
|
|
if (authInstance.check()) {
|
|
tokenRefreshManager.startRefreshTimer();
|
|
}
|
|
|
|
// Listen for successful login to start token refresh timer
|
|
window.addEventListener('auth-login-success', () => {
|
|
console.log('[Main] Login success event received, starting token refresh timer');
|
|
if (tokenRefreshManager) {
|
|
tokenRefreshManager.startRefreshTimer();
|
|
}
|
|
});
|
|
|
|
// Stop token refresh timer on logout
|
|
window.addEventListener('auth-logout', () => {
|
|
console.log('[Main] Logout event received, stopping token refresh timer');
|
|
if (tokenRefreshManager) {
|
|
tokenRefreshManager.stopRefreshTimer();
|
|
}
|
|
});
|
|
|
|
const loadingStore = LoadingStore();
|
|
|
|
axios.interceptors.request.use(
|
|
function (config) {
|
|
loadingStore.another_loading = true;
|
|
return config;
|
|
},
|
|
function (error) {
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
axios.interceptors.response.use(
|
|
function (response) {
|
|
loadingStore.another_loading = false;
|
|
return response;
|
|
},
|
|
async function (error) {
|
|
loadingStore.another_loading = false;
|
|
|
|
// Don't handle auth-related URLs to prevent infinite loops
|
|
const isAuthUrl = error.config && (error.config.url.includes('/api/auth/') || error.config.url.includes('/msauth/'));
|
|
|
|
// Handle 403 errors by attempting token refresh (but not for auth URLs)
|
|
if (error.response && error.response.status === 403 && !isAuthUrl) {
|
|
console.log('[Interceptor] 403 error detected, attempting token refresh...');
|
|
|
|
// Check if we have an authenticated user and authInstance is available
|
|
if (authInstance && authInstance.check && authInstance.check()) {
|
|
try {
|
|
// Use our custom AuthService to refresh tokens (both MSAL and classic)
|
|
const refreshResult = await AuthService.refreshToken(authInstance);
|
|
|
|
if (refreshResult.success && refreshResult.token) {
|
|
console.log('[Interceptor] Token refresh successful, updating auth and retrying request...');
|
|
|
|
// Update the auth token
|
|
authInstance.token(null, refreshResult.token, false);
|
|
|
|
// Update the original request with new token
|
|
error.config.headers['Authorization'] = `Bearer ${refreshResult.token}`;
|
|
|
|
// Retry the original request
|
|
return axios.request(error.config);
|
|
} else {
|
|
console.error('[Interceptor] Token refresh failed:', refreshResult.error);
|
|
throw new Error(refreshResult.error);
|
|
}
|
|
} catch (refreshError) {
|
|
console.error('[Interceptor] Token refresh process failed:', refreshError);
|
|
|
|
// If refresh fails, logout and redirect to login
|
|
try {
|
|
// Stop token refresh timer
|
|
window.dispatchEvent(new CustomEvent('auth-logout'));
|
|
|
|
await AuthService.logout();
|
|
if (authInstance && authInstance.logout) {
|
|
authInstance.logout({
|
|
redirect: '/auth/login'
|
|
});
|
|
} else {
|
|
window.location.href = '/auth/login';
|
|
}
|
|
} catch (logoutError) {
|
|
console.error('[Interceptor] Logout failed:', logoutError);
|
|
// Force redirect to login
|
|
window.location.href = '/auth/login';
|
|
}
|
|
|
|
return Promise.reject(refreshError);
|
|
}
|
|
} else {
|
|
console.log('[Interceptor] No authenticated user for non-auth 403, ignoring...');
|
|
}
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
}
|
|
);
|