refont back express
This commit is contained in:
7
backend/.env
Normal file
7
backend/.env
Normal file
@@ -0,0 +1,7 @@
|
||||
ALLOWED_ORIGIN=http://localhost:4300
|
||||
PORT=3333
|
||||
JWT_SECRET=d1bcf750e6246f1d75a2b32e3ff9ac7a8507b1d27462fc3223b966a86e3ef28762efcfc90a50e20b1888b1c8d7ce107260784b6d3ac9cb3662f499a7b272b1d926e3e0232de3581f25cde6e6da3dd0f62ee00fbe8bbfc3425c5abc0ad3b53f9b9c75875fe57629c9f1fe01ffb280d5605a54ab90ca15ae4cb6c43e298448e95bffd55582a16d18867d3c5db1cb316ba5fc9dfbdde1d8ef523a2d35f425aacd42286058801e79dc0b7c3fd3f9430ef3696e0fbcef5f28ba12ba3e38ee7e9b8f79d9ae51fb81f13528e9008d917d5be6145f3ab9a621dc89aef1f4df09bcdcce9f109f4f792623061ad1cfe541097fdf3695cfb72673ece58db49894d25f486e99
|
||||
DB_HOST=localhost
|
||||
DB_USER=eni
|
||||
DB_PASSWORD=gkAAUlq2e)0*ROLO
|
||||
DB_DATABASE=eni
|
||||
16
backend/config/cors.js
Normal file
16
backend/config/cors.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import dotenv from 'dotenv';
|
||||
import * as path from "node:path";
|
||||
|
||||
const envFile = `.env`;
|
||||
dotenv.config({ path: path.resolve(process.cwd(), envFile), override: true });
|
||||
|
||||
const allowedOrigin = process.env.ALLOWED_ORIGIN || 'http://localhost:4200';
|
||||
|
||||
const corsOptions = {
|
||||
origin: allowedOrigin,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: true,
|
||||
};
|
||||
|
||||
export default corsOptions;
|
||||
13
backend/config/db.js
Normal file
13
backend/config/db.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import mariadb from 'mariadb';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const pool = mariadb.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
export default pool;
|
||||
6
backend/controllers/apiController.js
Normal file
6
backend/controllers/apiController.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default function getConnect(req, res) {
|
||||
res.json({
|
||||
message: 'Connexion : OK',
|
||||
status: true
|
||||
});
|
||||
};
|
||||
143
backend/controllers/authController.js
Normal file
143
backend/controllers/authController.js
Normal file
@@ -0,0 +1,143 @@
|
||||
import pool from "../config/db.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
// Création d'un utilisateur
|
||||
export const register = async (req, res) => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const { email, firstname, lastname, password_hash } = req.body;
|
||||
if (!email || !firstname || !lastname || !password_hash) {
|
||||
return res.status(400).json({
|
||||
message: 'Tout les champs sont requis !',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
const existingUsers = await conn.query(
|
||||
'SELECT * FROM users WHERE email = ?',
|
||||
[email]
|
||||
);
|
||||
if (existingUsers.length > 0) {
|
||||
return res.status(409).json({
|
||||
message: 'L\'utilisateur existe déjà !',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
// Hash du mot de passe
|
||||
const hashedPassword = await bcrypt.hash(password_hash, 10);
|
||||
const result = await conn.query(
|
||||
'INSERT INTO users (email, firstname, lastname, password_hash) VALUES (?, ?, ?, ?, ?)',
|
||||
[email, firstname, lastname, hashedPassword]
|
||||
);
|
||||
res.status(201).json({
|
||||
message: 'L\'utilisateur à bien été enregistré !',
|
||||
status: true
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Erreur interne :', err);
|
||||
return res.status(500).json({
|
||||
message: 'Erreur interne du serveur.',
|
||||
status: false
|
||||
});
|
||||
} finally {
|
||||
if (conn) await conn.release();
|
||||
}
|
||||
};
|
||||
|
||||
// Connexion
|
||||
export const login = async (req, res) => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const { email, password } = req.body;
|
||||
// Chercher l'utilisateur
|
||||
const users = await conn.query(
|
||||
'SELECT * FROM users WHERE email = ?',
|
||||
[email]
|
||||
);
|
||||
if (users.length === 0) {
|
||||
return res.status(401).json({
|
||||
message: 'Identifiant incorrect',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
const user = users[0];
|
||||
// Verify password
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password_hash);
|
||||
if (!isPasswordValid) {
|
||||
return res.status(401).json({
|
||||
message: 'Identifiant incorrect',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
// Generate JWT token
|
||||
const token = jwt.sign(
|
||||
{
|
||||
id: user.id,
|
||||
},
|
||||
process.env.JWT_SECRET || 'fallback_secret',
|
||||
{ expiresIn: '12h' }
|
||||
);
|
||||
await conn.query(
|
||||
'UPDATE users SET updated_at = CURRENT_TIMESTAMP WHERE id = ?',
|
||||
[user.id]
|
||||
);
|
||||
await setLogs(email + " s'est connecté !")
|
||||
res.cookie('jwt', token, {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'Strict',
|
||||
maxAge: 12 * 60 * 60 * 1000
|
||||
});
|
||||
res.json({
|
||||
message: 'Connexion réussie',
|
||||
status: true
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Erreur interne :', err);
|
||||
return res.status(500).json({
|
||||
message: 'Erreur interne du serveur.',
|
||||
status: false
|
||||
});
|
||||
} finally {
|
||||
if (conn) await conn.release();
|
||||
}
|
||||
};
|
||||
|
||||
// Déconnecter l'utilisateur
|
||||
export const logout = (req, res) => {
|
||||
res.clearCookie('jwt', {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'Strict',
|
||||
});
|
||||
res.status(200).json({
|
||||
message: 'Successfully logged out',
|
||||
status: true
|
||||
});
|
||||
};
|
||||
|
||||
// Vérification de la connexion sur la page pour guard angular
|
||||
export const checkAuth = (req, res) => {
|
||||
const token = req.cookies.jwt;
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
message: 'Non identifié',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
try {
|
||||
req.user = jwt.verify(token, process.env.JWT_SECRET);
|
||||
res.status(200).json({
|
||||
message: 'identifié',
|
||||
status: true
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Erreur interne :', err);
|
||||
return res.status(500).json({
|
||||
message: 'Erreur interne du serveur.',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
};
|
||||
24
backend/middleware/apiKeyMiddleware.js
Normal file
24
backend/middleware/apiKeyMiddleware.js
Normal file
@@ -0,0 +1,24 @@
|
||||
export const apiKeyMiddleware = async (req, res, next) => {
|
||||
const authHeader = req.header('Authorization');
|
||||
if (!authHeader) {
|
||||
return res.status(403).json({
|
||||
message: 'Forbidden: No API Key provided',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
try {
|
||||
if (authHeader !== "9IgFg8cnUS4XJE7Q91A0XjrWnjbnBhdk98jcI6fV1n6NAEYz31SHicge8Vkq0bCGvfKsjylb19ouri6FFUeNC1PgPvwrNCC3G5jcz4PLInlFanzf47hCsBJw4IXuhNHC"){
|
||||
return res.status(403).json({
|
||||
message: 'Forbidden: Invalid API Key',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
next();
|
||||
} catch (err) {
|
||||
console.error('Erreur interne :', err);
|
||||
return res.status(500).json({
|
||||
message: 'Erreur interne du serveur.',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
};
|
||||
25
backend/middleware/tokenJWTMiddleware.js
Normal file
25
backend/middleware/tokenJWTMiddleware.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
export const verifyToken = async (req, res, next) => {
|
||||
// Récupérer le token depuis le cookie 'jxwt'
|
||||
const token = req.cookies['jwt'];
|
||||
|
||||
if (!token) {
|
||||
return res.status(403).json({
|
||||
message: 'Token is required',
|
||||
status: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Vérifier le token
|
||||
jwt.verify(token, process.env.JWT_SECRET || 'fallback_secret', (err, decoded) => {
|
||||
if (err) {
|
||||
return res.status(401).json({
|
||||
message: 'Invalid or expired token',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
req.user = decoded;
|
||||
next();
|
||||
});
|
||||
};
|
||||
24
backend/package.json
Normal file
24
backend/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "api_eni_angular",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "API ENI Angular",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
},
|
||||
"author": "Johan Leroy",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^3.0.2",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mariadb": "^3.4.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"url": "^0.11.4",
|
||||
"uuid": "^11.1.0"
|
||||
}
|
||||
}
|
||||
53
backend/routes/apiRoutes.js
Normal file
53
backend/routes/apiRoutes.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import apiController from "../controllers/apiController.js";
|
||||
import {
|
||||
register,
|
||||
login,
|
||||
checkAuth,
|
||||
logout,
|
||||
} from "../controllers/authController.js";
|
||||
import {verifyToken} from "../middleware/tokenJWTMiddleware.js";
|
||||
import multer from "multer";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import path from "node:path";
|
||||
|
||||
router.get('', apiController);
|
||||
|
||||
// Upload
|
||||
const generateFileName = (originalName) => {
|
||||
const ext = path.extname(originalName);
|
||||
const now = new Date();
|
||||
const timestamp = now.getFullYear().toString() +
|
||||
String(now.getMonth() + 1).padStart(2, '0') +
|
||||
String(now.getDate()).padStart(2, '0') +
|
||||
String(now.getHours()).padStart(2, '0') +
|
||||
String(now.getMinutes()).padStart(2, '0') +
|
||||
String(now.getSeconds()).padStart(2, '0');
|
||||
const uuid = uuidv4();
|
||||
return `${timestamp}_${uuid}${ext}`;
|
||||
};
|
||||
const storage = multer.diskStorage({
|
||||
destination: function (req, file, cb) {
|
||||
cb(null, 'uploads/'); // Stockage des fichiers dans le dossier uploads/
|
||||
},
|
||||
filename: function (req, file, cb) {
|
||||
cb(null, generateFileName(file.originalname));
|
||||
}
|
||||
});
|
||||
const upload = multer({ storage: storage });
|
||||
router.post('/upload', verifyToken, upload.single('file'), (req, res) => {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ message: 'Aucun fichier fourni' });
|
||||
}
|
||||
const filePath = `/uploads/${req.file.filename}`;
|
||||
res.json({ filePath });
|
||||
});
|
||||
|
||||
// Authentification et utilisateur
|
||||
router.post('/auth/register', register);
|
||||
router.post('/auth/login', login);
|
||||
router.post('/auth/logout', logout);
|
||||
router.get('/auth/check-auth', verifyToken, checkAuth);
|
||||
|
||||
export default router;
|
||||
82
backend/server.js
Normal file
82
backend/server.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import apiRoutes from './routes/apiRoutes.js';
|
||||
import corsOptions from './config/cors.js'
|
||||
import {apiKeyMiddleware} from './middleware/apiKeyMiddleware.js';
|
||||
import dotenv from 'dotenv';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import pool from "./config/db.js";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const envFile = `.env`;
|
||||
dotenv.config({ path: path.resolve(process.cwd(), envFile), override: true });
|
||||
|
||||
const app = express();
|
||||
|
||||
// Utiliser CORS
|
||||
app.use(cors(corsOptions));
|
||||
|
||||
// Utilisation des cookies
|
||||
app.use(cookieParser());
|
||||
|
||||
// Middleware pour parser les corps de requêtes JSON
|
||||
app.use(express.json());
|
||||
|
||||
// Utilisation des fichiers/images
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
||||
|
||||
// Middleware pour vérifier la clé API (Authorization)
|
||||
app.use('/', apiKeyMiddleware);
|
||||
|
||||
// Utiliser les routes API
|
||||
app.use('/', apiRoutes);
|
||||
|
||||
// Middleware pour les routes non trouvées
|
||||
app.use((req, res) => {
|
||||
res.status(404).json({
|
||||
message: 'Forbidden: Invalid Request',
|
||||
status: false
|
||||
});
|
||||
});
|
||||
|
||||
// Test de conenxion à la base de donnée
|
||||
const testDatabaseConnection = async () => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
console.log('✅ Connexion à la base de données réussie ! 🎉');
|
||||
} catch (err) {
|
||||
console.error('❌ Erreur de connexion à la base de données :', err.message);
|
||||
throw new Error('⛔ Impossible de se connecter à la base de données.');
|
||||
} finally {
|
||||
if (conn) await conn.end();
|
||||
}
|
||||
};
|
||||
|
||||
// Lancer le serveur
|
||||
const startServer = async () => {
|
||||
while (true) {
|
||||
try {
|
||||
console.log(`🚀 Lancement de l'API en cours... 🔧`);
|
||||
await testDatabaseConnection();
|
||||
app.listen(process.env.PORT, () => {
|
||||
console.log(`📢 NODE_ENV = ${process.env.NODE_ENV} 🌍`);
|
||||
console.log(`📢 Chargement du fichier : ${envFile} 📄`);
|
||||
console.log(`🚀 API démarrée sur le port ${process.env.PORT} 🎯`);
|
||||
console.log(`🌍 Allowed Origin : ${process.env.ALLOWED_ORIGIN} 🔗`);
|
||||
console.log(`✅ L'API est lancée et prête à l'emploi ! 🎉`);
|
||||
});
|
||||
break;
|
||||
} catch (err) {
|
||||
console.error('❌ Le serveur n’a pas pu démarrer :', err.message);
|
||||
console.log('⏳ Nouvelle tentative de démarrage dans 5 secondes... 🔄');
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
startServer();
|
||||
|
||||
Reference in New Issue
Block a user