VigilanzaTurni/server/localAuth.ts
marco370 c7c0830780 Improve local login handling with Passport.js authentication
Update the `/api/local-login` route to use Passport.js middleware for robust local authentication, including error handling for authentication failures and successful login.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e5565357-90e1-419f-b9a8-6ee8394636df
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e5565357-90e1-419f-b9a8-6ee8394636df/WbUtQAg
2025-10-23 15:21:02 +00:00

194 lines
5.6 KiB
TypeScript

// Sistema autenticazione locale per deployment server esterno (non-Replit)
import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import session from "express-session";
import type { Express } from "express";
import connectPg from "connect-pg-simple";
import { storage } from "./storage";
// Credenziali admin di default per demo/sviluppo
const DEFAULT_ADMIN_EMAIL = "admin@vt.alfacom.it";
const DEFAULT_ADMIN_PASSWORD = "admin123"; // CAMBIARE IN PRODUZIONE!
const DEFAULT_ADMIN_ID = "local-admin-vt";
export function getSession() {
const sessionTtl = 7 * 24 * 60 * 60 * 1000; // 1 settimana
const pgStore = connectPg(session);
const sessionStore = new pgStore({
conString: process.env.DATABASE_URL,
createTableIfMissing: false,
ttl: sessionTtl,
tableName: "sessions",
});
return session({
secret: process.env.SESSION_SECRET!,
store: sessionStore,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: sessionTtl,
},
});
}
async function initDefaultAdmin() {
try {
const bcrypt = await import("bcrypt");
const users = await storage.getAllUsers();
const existingAdmin = users.find((u: any) => u.email === DEFAULT_ADMIN_EMAIL);
if (existingAdmin) {
// Admin esiste: controlla se ha passwordHash
if (!existingAdmin.passwordHash) {
console.log(`🔄 [LocalAuth] Aggiornamento password hash per admin esistente...`);
const passwordHash = await bcrypt.hash(DEFAULT_ADMIN_PASSWORD, 10);
await storage.upsertUser({
id: existingAdmin.id,
email: existingAdmin.email,
firstName: existingAdmin.firstName || "Admin",
lastName: existingAdmin.lastName || "Sistema",
profileImageUrl: existingAdmin.profileImageUrl,
passwordHash,
});
console.log(`✅ [LocalAuth] Password hash aggiornato per: ${DEFAULT_ADMIN_EMAIL}`);
}
} else {
// Admin non esiste: crealo
const passwordHash = await bcrypt.hash(DEFAULT_ADMIN_PASSWORD, 10);
await storage.upsertUser({
id: DEFAULT_ADMIN_ID,
email: DEFAULT_ADMIN_EMAIL,
firstName: "Admin",
lastName: "Sistema",
profileImageUrl: null,
passwordHash,
});
// Imposta ruolo admin
await storage.updateUserRole(DEFAULT_ADMIN_ID, "admin");
console.log(`✅ [LocalAuth] Admin di default creato: ${DEFAULT_ADMIN_EMAIL}`);
}
} catch (error) {
console.error("❌ [LocalAuth] Errore creazione admin:", error);
}
}
export async function setupLocalAuth(app: Express) {
app.set("trust proxy", 1);
app.use(getSession());
app.use(passport.initialize());
app.use(passport.session());
// Inizializza admin di default
await initDefaultAdmin();
// Strategia passport-local con password hash bcrypt
passport.use(new LocalStrategy(
{ usernameField: "email" },
async (email, password, done) => {
try {
const users = await storage.getAllUsers();
const user = users.find((u: any) => u.email === email);
if (!user) {
return done(null, false, { message: "Credenziali non valide" });
}
if (!user.passwordHash) {
return done(null, false, { message: "Credenziali non valide" });
}
// Verifica password con bcrypt
const bcrypt = await import("bcrypt");
const isValidPassword = await bcrypt.compare(password, user.passwordHash);
if (!isValidPassword) {
return done(null, false, { message: "Credenziali non valide" });
}
return done(null, { id: user.id, email: user.email });
} catch (error) {
return done(error);
}
}
));
passport.serializeUser((user: any, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id: string, done) => {
try {
const users = await storage.getAllUsers();
const user = users.find((u: any) => u.id === id);
done(null, user || null);
} catch (error) {
done(error);
}
});
// Route login GET (redirect a pagina login frontend)
app.get("/api/login", (req, res) => {
res.redirect("/login");
});
// Route login locale POST
app.post("/api/local-login", (req, res, next) => {
passport.authenticate("local", (err: any, user: any, info: any) => {
if (err) {
return res.status(500).json({
success: false,
message: "Errore durante il login"
});
}
if (!user) {
return res.status(401).json({
success: false,
message: info?.message || "Email o password non corretti"
});
}
req.login(user, (loginErr) => {
if (loginErr) {
return res.status(500).json({
success: false,
message: "Errore durante il login"
});
}
return res.json({
success: true,
user: req.user,
message: "Login effettuato con successo"
});
});
})(req, res, next);
});
// Route logout
app.get("/api/logout", (req, res) => {
req.logout(() => {
res.redirect("/");
});
});
console.log("✅ [LocalAuth] Sistema autenticazione locale attivato");
console.log(`📧 Admin email: ${DEFAULT_ADMIN_EMAIL}`);
console.log(`🔑 Admin password: ${DEFAULT_ADMIN_PASSWORD}`);
console.log(`🔗 Login page: /login`);
}
export const isAuthenticated = async (req: any, res: any, next: any) => {
if (!req.isAuthenticated()) {
return res.status(401).json({ message: "Unauthorized" });
}
next();
};