433 lines
5.6 KiB
JavaScript
433 lines
5.6 KiB
JavaScript
// ===============================
|
|
// AUTH.JS — Login + Token + Redirect + Sessione browser
|
|
// ===============================
|
|
|
|
// parseJwt DEVE essere globale
|
|
function parseJwt(token) {
|
|
try {
|
|
const base64Url = token.split(".")[1];
|
|
|
|
const base64 = base64Url
|
|
.replace(/-/g, "+")
|
|
.replace(/_/g, "/");
|
|
|
|
const jsonPayload = decodeURIComponent(
|
|
atob(base64)
|
|
.split("")
|
|
.map(
|
|
(c) =>
|
|
"%" +
|
|
("00" + c.charCodeAt(0).toString(16)).slice(-2),
|
|
)
|
|
.join(""),
|
|
);
|
|
|
|
return JSON.parse(jsonPayload);
|
|
|
|
} catch (e) {
|
|
console.error("Errore parseJwt:", e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
(() => {
|
|
|
|
const LOGIN_ENDPOINT = "/auth/login";
|
|
const TOKEN_KEY = "token";
|
|
|
|
|
|
// -------------------------------
|
|
// TOKEN STORAGE
|
|
// -------------------------------
|
|
|
|
function saveToken(token) {
|
|
try {
|
|
localStorage.setItem(TOKEN_KEY, token);
|
|
} catch (err) {
|
|
console.error("Errore salvataggio token:", err);
|
|
}
|
|
}
|
|
|
|
|
|
function getToken() {
|
|
try {
|
|
return localStorage.getItem(TOKEN_KEY) || "";
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
|
|
function clearToken() {
|
|
try {
|
|
localStorage.removeItem(TOKEN_KEY);
|
|
sessionStorage.removeItem("app_open");
|
|
} catch {}
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// LOGIN
|
|
// -------------------------------
|
|
|
|
async function login(email, password) {
|
|
|
|
try {
|
|
|
|
const res = await fetch(LOGIN_ENDPOINT, {
|
|
|
|
method: "POST",
|
|
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
|
|
body: JSON.stringify({
|
|
email,
|
|
password,
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
const msg = await res.text();
|
|
|
|
throw new Error(
|
|
msg || "Credenziali non valide"
|
|
);
|
|
|
|
}
|
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
|
if (!data?.token) {
|
|
|
|
throw new Error(
|
|
"Token mancante nella risposta"
|
|
);
|
|
|
|
}
|
|
|
|
|
|
saveToken(data.token);
|
|
|
|
|
|
// segna apertura applicazione
|
|
sessionStorage.setItem(
|
|
"app_open",
|
|
"1"
|
|
);
|
|
|
|
|
|
window.dispatchEvent(
|
|
new CustomEvent(
|
|
"login:success",
|
|
{
|
|
detail: data,
|
|
}
|
|
)
|
|
);
|
|
|
|
|
|
scheduleAutoLogout();
|
|
|
|
|
|
return data;
|
|
|
|
|
|
} catch(err) {
|
|
|
|
console.error(
|
|
"Errore login:",
|
|
err
|
|
);
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// CHECK LOGIN
|
|
// -------------------------------
|
|
|
|
function isLoggedIn() {
|
|
|
|
|
|
// nuova apertura browser/tab
|
|
if (
|
|
!sessionStorage.getItem("app_open")
|
|
) {
|
|
|
|
console.log(
|
|
"[AUTH] nuova apertura browser"
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
const token = getToken();
|
|
|
|
|
|
if (!token) {
|
|
|
|
console.log(
|
|
"[AUTH] token assente"
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
const payload = parseJwt(token);
|
|
|
|
|
|
if (!payload?.exp) {
|
|
|
|
console.log(
|
|
"[AUTH] token senza exp"
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
const valid =
|
|
payload.exp * 1000 > Date.now();
|
|
|
|
|
|
console.log(
|
|
"[AUTH CHECK]",
|
|
{
|
|
valid,
|
|
user: payload.name,
|
|
exp: new Date(
|
|
payload.exp * 1000
|
|
).toISOString()
|
|
}
|
|
);
|
|
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// USER INFO
|
|
// -------------------------------
|
|
|
|
function getUser() {
|
|
|
|
const token = getToken();
|
|
|
|
if (!token) {
|
|
return null;
|
|
}
|
|
|
|
return parseJwt(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// REQUIRE AUTH
|
|
// -------------------------------
|
|
|
|
function requireAuth(
|
|
redirectUrl = "/login"
|
|
) {
|
|
|
|
|
|
if (isLoggedIn()) {
|
|
return true;
|
|
}
|
|
|
|
|
|
clearToken();
|
|
|
|
|
|
const currentPath =
|
|
window.location.pathname +
|
|
window.location.search +
|
|
window.location.hash;
|
|
|
|
|
|
const separator =
|
|
redirectUrl.includes("?")
|
|
? "&"
|
|
: "?";
|
|
|
|
|
|
window.location.replace(
|
|
`${redirectUrl}${separator}redirect=${encodeURIComponent(currentPath)}`
|
|
);
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// AUTO LOGOUT JWT
|
|
// -------------------------------
|
|
|
|
let autoLogoutTimer = null;
|
|
|
|
|
|
function scheduleAutoLogout() {
|
|
|
|
|
|
clearTimeout(
|
|
autoLogoutTimer
|
|
);
|
|
|
|
|
|
const token = getToken();
|
|
|
|
|
|
if (!token) {
|
|
return;
|
|
}
|
|
|
|
|
|
const payload =
|
|
parseJwt(token);
|
|
|
|
|
|
const expSec =
|
|
payload?.exp;
|
|
|
|
|
|
if (!expSec) {
|
|
return;
|
|
}
|
|
|
|
|
|
const timeout =
|
|
expSec * 1000 -
|
|
Date.now();
|
|
|
|
|
|
|
|
if (timeout <= 0) {
|
|
|
|
window.AppAuth.logout?.({
|
|
redirect:true
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
autoLogoutTimer =
|
|
setTimeout(() => {
|
|
|
|
window.AppAuth.logout?.({
|
|
redirect:true
|
|
});
|
|
|
|
}, timeout);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// EXPORT
|
|
// -------------------------------
|
|
|
|
window.AppAuth =
|
|
Object.freeze({
|
|
|
|
login,
|
|
|
|
logout:(opts)=>
|
|
window.AppAuthLogout?.logout(opts),
|
|
|
|
isLoggedIn,
|
|
|
|
getUser,
|
|
|
|
requireAuth,
|
|
|
|
scheduleAutoLogout,
|
|
|
|
});
|
|
|
|
|
|
|
|
// -------------------------------
|
|
// INIT
|
|
// -------------------------------
|
|
|
|
function init() {
|
|
|
|
|
|
// marca questa apertura browser
|
|
sessionStorage.setItem(
|
|
"app_open",
|
|
"1"
|
|
);
|
|
|
|
|
|
if (isLoggedIn()) {
|
|
|
|
scheduleAutoLogout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
document.readyState === "loading"
|
|
) {
|
|
|
|
document.addEventListener(
|
|
"DOMContentLoaded",
|
|
init
|
|
);
|
|
|
|
} else {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
// chiusura pagina/tab
|
|
window.addEventListener(
|
|
"pagehide",
|
|
() => {
|
|
|
|
sessionStorage.removeItem(
|
|
"app_open"
|
|
);
|
|
|
|
}
|
|
);
|
|
|
|
|
|
})();
|