From 2c656aadf02a2183614d39ba7ec8decf3504cd4e Mon Sep 17 00:00:00 2001 From: el Date: Wed, 2 Apr 2025 00:40:31 +0200 Subject: [PATCH] login --- backend/package-lock.json | 183 ++++++++++++++++++++++++++++--- backend/package.json | 6 +- backend/src/index.ts | 7 +- backend/src/routes/userRoutes.ts | 69 +++++++++--- frontend | 2 +- 5 files changed, 235 insertions(+), 32 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 1c8af33..417e06b 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -11,10 +11,14 @@ "dependencies": { "@prisma/client": "^5.0.0", "@types/bcryptjs": "^2.4.6", + "@types/cookie-parser": "^1.4.8", + "@types/jsonwebtoken": "^9.0.9", "bcryptjs": "^3.0.2", + "cookie-parser": "^1.4.7", "cors": "^2.8.5", "dotenv": "^16.0.3", - "express": "^4.18.2" + "express": "^4.18.2", + "jsonwebtoken": "^9.0.2" }, "devDependencies": { "@types/cors": "^2.8.13", @@ -172,7 +176,6 @@ "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, "license": "MIT", "dependencies": { "@types/connect": "*", @@ -183,12 +186,20 @@ "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.8.tgz", + "integrity": "sha512-l37JqFrOJ9yQfRQkljb41l0xVphc7kg5JTjjr+pLRZ0IyZ49V4BQ8vbF4Ut2C2e+WH4al3xD3ZwYwIUfnbT4NQ==", + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", @@ -203,7 +214,6 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", @@ -216,7 +226,6 @@ "version": "4.19.6", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -229,21 +238,34 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, "node_modules/@types/node": { "version": "18.19.86", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -253,21 +275,18 @@ "version": "6.9.18", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", - "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -278,7 +297,6 @@ "version": "1.15.7", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -443,6 +461,12 @@ "node": ">=8" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -550,6 +574,28 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -650,6 +696,15 @@ "xtend": "^4.0.0" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1061,6 +1116,97 @@ "node": ">=0.12.0" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -1432,6 +1578,18 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", @@ -1782,7 +1940,6 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, "license": "MIT" }, "node_modules/unpipe": { diff --git a/backend/package.json b/backend/package.json index 1a323c0..aeb1bd1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -16,10 +16,14 @@ "dependencies": { "@prisma/client": "^5.0.0", "@types/bcryptjs": "^2.4.6", + "@types/cookie-parser": "^1.4.8", + "@types/jsonwebtoken": "^9.0.9", "bcryptjs": "^3.0.2", + "cookie-parser": "^1.4.7", "cors": "^2.8.5", "dotenv": "^16.0.3", - "express": "^4.18.2" + "express": "^4.18.2", + "jsonwebtoken": "^9.0.2" }, "devDependencies": { "@types/cors": "^2.8.13", diff --git a/backend/src/index.ts b/backend/src/index.ts index 635a510..e05cc89 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -5,6 +5,7 @@ import { PrismaClient } from '@prisma/client'; import userRoutes from './routes/userRoutes'; import pageRoutes from './routes/pageRoutes'; import blockRoutes from './routes/blockRoutes'; +import cookieParser from 'cookie-parser'; // Chargement des variables d'environnement dotenv.config(); @@ -17,12 +18,14 @@ const port = process.env.PORT || 3001; app.use(cors({ origin: 'http://localhost:3000', credentials: true, - methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], - allowedHeaders: ['Content-Type', 'Authorization'] + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'], + allowedHeaders: ['Content-Type', 'Authorization', 'Cookie'], + exposedHeaders: ['Set-Cookie'], })); // Middleware app.use(express.json()); +app.use(cookieParser()); // Routes app.use('/api/users', userRoutes); diff --git a/backend/src/routes/userRoutes.ts b/backend/src/routes/userRoutes.ts index 3e049a8..eac0156 100644 --- a/backend/src/routes/userRoutes.ts +++ b/backend/src/routes/userRoutes.ts @@ -1,9 +1,11 @@ import express from 'express'; import { PrismaClient } from '@prisma/client'; import bcrypt from 'bcryptjs'; +import jwt from 'jsonwebtoken'; const router = express.Router(); const prisma = new PrismaClient(); +const JWT_SECRET = process.env.JWT_SECRET || 'votre-secret-jwt'; // Supprimer un utilisateur (route de développement) router.delete('/:email', async (req, res) => { @@ -23,28 +25,44 @@ router.delete('/:email', async (req, res) => { router.post('/register', async (req, res) => { try { const { email, password, name } = req.body; - - // Vérification si l'utilisateur existe déjà + console.log('Tentative d\'inscription:', { email, name }); + + // Vérification des champs requis + if (!email || !password) { + return res.status(400).json({ message: 'Email et mot de passe requis' }); + } + const existingUser = await prisma.user.findUnique({ where: { email } }); if (existingUser) { + console.log('Email déjà utilisé:', email); return res.status(400).json({ message: 'Cet email est déjà utilisé' }); } - // Hashage du mot de passe const hashedPassword = await bcrypt.hash(password, 10); + console.log('Création de l\'utilisateur...'); - // Création de l'utilisateur const user = await prisma.user.create({ data: { email, password: hashedPassword, - name + name: name || email.split('@')[0] } }); + console.log('Utilisateur créé avec succès:', user.id); + + const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '24h' }); + res.cookie('token', token, { + httpOnly: true, + secure: false, + sameSite: 'lax', + path: '/', + maxAge: 24 * 60 * 60 * 1000 + }); + res.status(201).json({ id: user.id, email: user.email, @@ -52,7 +70,10 @@ router.post('/register', async (req, res) => { }); } catch (error) { console.error('Erreur lors de l\'inscription:', error); - res.status(500).json({ message: 'Erreur lors de l\'inscription' }); + res.status(500).json({ + message: 'Erreur lors de l\'inscription', + details: error instanceof Error ? error.message : 'Erreur inconnue' + }); } }); @@ -62,7 +83,6 @@ router.post('/login', async (req, res) => { const { email, password } = req.body; console.log('Tentative de connexion pour:', email); - // Recherche de l'utilisateur const user = await prisma.user.findUnique({ where: { email } }); @@ -73,8 +93,6 @@ router.post('/login', async (req, res) => { } console.log('Utilisateur trouvé, vérification du mot de passe'); - - // Vérification du mot de passe const validPassword = await bcrypt.compare(password, user.password); console.log('Mot de passe valide:', validPassword); @@ -82,6 +100,15 @@ router.post('/login', async (req, res) => { return res.status(400).json({ message: 'Email ou mot de passe incorrect' }); } + const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '24h' }); + res.cookie('token', token, { + httpOnly: true, + secure: false, + sameSite: 'lax', + path: '/', + maxAge: 24 * 60 * 60 * 1000 // 24 heures + }); + res.json({ id: user.id, email: user.email, @@ -93,17 +120,29 @@ router.post('/login', async (req, res) => { } }); +// Déconnexion +router.post('/logout', (req, res) => { + res.clearCookie('token', { + httpOnly: true, + secure: false, + sameSite: 'lax', + path: '/' + }); + res.json({ message: 'Déconnexion réussie' }); +}); + // Vérifier l'état de l'authentification router.get('/me', async (req, res) => { try { - const { email } = req.query; - - if (!email) { - return res.status(400).json({ message: 'Email requis' }); + const token = req.cookies.token; + + if (!token) { + return res.status(401).json({ message: 'Non authentifié' }); } + const decoded = jwt.verify(token, JWT_SECRET) as { userId: string }; const user = await prisma.user.findUnique({ - where: { email: email as string } + where: { id: decoded.userId } }); if (!user) { @@ -117,7 +156,7 @@ router.get('/me', async (req, res) => { }); } catch (error) { console.error('Erreur lors de la vérification de l\'authentification:', error); - res.status(500).json({ message: 'Erreur lors de la vérification de l\'authentification' }); + res.status(401).json({ message: 'Session invalide' }); } }); diff --git a/frontend b/frontend index d2ead43..57c6cda 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit d2ead43b4fcaa3a04ca6908c58047691771c725e +Subproject commit 57c6cda469a86e432062f33f2e432be7174d7c7c