Checkpoint: Migration complète vers l'authentification locale avec email/mot de passe
✅ Modifications apportées : - Remplacement de l'authentification OAuth Manus par un système local - Ajout des champs email, password, emailVerified dans la table users - Implémentation du hashage des mots de passe avec bcrypt - Création des procédures auth.login et auth.register - Mise à jour du système de context pour utiliser JWT - Création des pages de connexion et d'inscription - Mise à jour de la page AdminUsers pour créer des utilisateurs avec mot de passe - Ajout de la protection des routes d'administration (vérification du rôle admin) ✅ Tests effectués : - Connexion avec email/mot de passe ✓ - Création d'utilisateurs via l'interface d'administration ✓ - Protection des routes (seuls les admins peuvent accéder au dashboard) ✓ - Redirection automatique après connexion ✓ Note : Les fichiers OAuth Manus originaux ont été conservés pour référence mais ne sont plus utilisés.
This commit is contained in:
@@ -42,7 +42,7 @@ export function getSessionCookieOptions(
|
||||
return {
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
sameSite: "none",
|
||||
sameSite: "lax",
|
||||
secure: isSecureRequest(req),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const ENV = {
|
||||
appId: process.env.VITE_APP_ID ?? "",
|
||||
cookieSecret: process.env.JWT_SECRET ?? "",
|
||||
jwtSecret: process.env.JWT_SECRET ?? "",
|
||||
databaseUrl: process.env.DATABASE_URL ?? "",
|
||||
oAuthServerUrl: process.env.OAUTH_SERVER_URL ?? "",
|
||||
ownerOpenId: process.env.OWNER_OPEN_ID ?? "",
|
||||
|
||||
@@ -2,6 +2,7 @@ import "dotenv/config";
|
||||
import express from "express";
|
||||
import { createServer } from "http";
|
||||
import net from "net";
|
||||
import cookieParser from "cookie-parser";
|
||||
import { createExpressMiddleware } from "@trpc/server/adapters/express";
|
||||
import { registerOAuthRoutes } from "./oauth";
|
||||
import { appRouter } from "../routers";
|
||||
@@ -30,6 +31,8 @@ async function findAvailablePort(startPort: number = 3000): Promise<number> {
|
||||
async function startServer() {
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
// Configure cookie parser
|
||||
app.use(cookieParser());
|
||||
// Configure body parser with larger size limit for file uploads
|
||||
app.use(express.json({ limit: "50mb" }));
|
||||
app.use(express.urlencoded({ limit: "50mb", extended: true }));
|
||||
|
||||
@@ -55,7 +55,7 @@ export const appRouter = router({
|
||||
|
||||
// Définir le cookie de session
|
||||
const cookieOptions = getSessionCookieOptions(ctx.req);
|
||||
ctx.res.cookie(COOKIE_NAME, token, cookieOptions);
|
||||
ctx.res.cookie(COOKIE_NAME, token, { ...cookieOptions, maxAge: 30 * 24 * 60 * 60 * 1000 }); // 30 jours
|
||||
|
||||
return { success: true, userId };
|
||||
}),
|
||||
@@ -79,8 +79,16 @@ export const appRouter = router({
|
||||
throw new TRPCError({ code: 'FORBIDDEN', message: 'Votre compte a été désactivé' });
|
||||
}
|
||||
|
||||
// Vérifier que le mot de passe existe
|
||||
if (!user.password) {
|
||||
console.error('[LOGIN] User has no password:', user.email);
|
||||
throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Email ou mot de passe incorrect' });
|
||||
}
|
||||
|
||||
// Vérifier le mot de passe
|
||||
console.log('[LOGIN] Verifying password for:', user.email);
|
||||
const isValid = await verifyPassword(input.password, user.password);
|
||||
console.log('[LOGIN] Password valid:', isValid);
|
||||
if (!isValid) {
|
||||
throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Email ou mot de passe incorrect' });
|
||||
}
|
||||
@@ -93,7 +101,7 @@ export const appRouter = router({
|
||||
|
||||
// Définir le cookie de session
|
||||
const cookieOptions = getSessionCookieOptions(ctx.req);
|
||||
ctx.res.cookie(COOKIE_NAME, token, cookieOptions);
|
||||
ctx.res.cookie(COOKIE_NAME, token, { ...cookieOptions, maxAge: 30 * 24 * 60 * 60 * 1000 }); // 30 jours
|
||||
|
||||
return { success: true, user: { id: user.id, email: user.email, name: user.name, role: user.role } };
|
||||
}),
|
||||
@@ -626,13 +634,32 @@ export const appRouter = router({
|
||||
}),
|
||||
|
||||
create: adminProcedure.input(z.object({
|
||||
openId: z.string().min(1),
|
||||
email: z.string().email(),
|
||||
password: z.string().min(6),
|
||||
name: z.string().optional(),
|
||||
email: z.string().email().optional(),
|
||||
role: z.enum(["user", "admin"]).default("user"),
|
||||
isActive: z.boolean().default(true),
|
||||
})).mutation(async ({ input }) => {
|
||||
await db.createUser(input);
|
||||
const { hashPassword } = await import("./_core/auth");
|
||||
|
||||
// Vérifier si l'utilisateur existe déjà
|
||||
const existingUser = await db.getUserByEmail(input.email);
|
||||
if (existingUser) {
|
||||
throw new TRPCError({ code: 'CONFLICT', message: 'Un compte existe déjà avec cet email' });
|
||||
}
|
||||
|
||||
// Hasher le mot de passe
|
||||
const hashedPassword = await hashPassword(input.password);
|
||||
|
||||
// Créer l'utilisateur
|
||||
await db.createUser({
|
||||
email: input.email,
|
||||
password: hashedPassword,
|
||||
name: input.name,
|
||||
emailVerified: false,
|
||||
role: input.role,
|
||||
isActive: input.isActive,
|
||||
});
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user