SQLite / backend/server.js
Structure de la table "Comptes"
- Intégrité des données : Le champ
mail possède une contrainte UNIQUE stricte pour prévenir les conflits d'inscription.
- Sécurité cryptographique : Le champ
mot_de_passe est conçu pour stocker l'empreinte générée par Bcrypt, et non la chaîne de caractères brute.
- Contrôle d'accès (RBAC) : Le champ
role détermine le niveau de privilège de l'entité (etudiant, enseignant, admin).
/* Initialisation SQLite (server.js) */
CREATE TABLE IF NOT EXISTS Comptes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT NOT NULL,
prenom TEXT NOT NULL,
mail TEXT UNIQUE NOT NULL,
mot_de_passe TEXT NOT NULL,
role TEXT NOT NULL,
classe TEXT
);
Node.js / backend/server.js
Traitement de l'Inscription (Registration)
- Vérification de redondance : L'API interroge la base de données pour confirmer la disponibilité de l'adresse e-mail avant tout traitement.
- Hachage : Utilisation de
bcrypt.hash() avec un facteur de coût (salt rounds) fixé à 10 pour générer une empreinte sécurisée.
- Injection SQL évitée : L'insertion des données s'effectue via une requête préparée avec des paramètres liés (paramètres
?).
app.post('/api/register', async (req, res) => {
const { nom, prenom, mail, password, classe } = req.body;
// Vérification de l'existence de l'email
const existing = await db.all('SELECT * FROM Comptes WHERE mail = ?', [mail]);
if (existing.length > 0) return res.status(400).json({ message: "Email déjà utilisé" });
// Hachage du mot de passe
const hashedPassword = await bcrypt.hash(password, 10);
// Insertion sécurisée
await db.run(
'INSERT INTO Comptes (nom, prenom, mail, mot_de_passe, role, classe) VALUES (?, ?, ?, ?, ?, ?)',
[nom, prenom, mail, hashedPassword, 'etudiant', classe || 'MMI-A1']
);
res.status(201).json({ message: "Compte créé" });
});
Node.js / backend/server.js
Authentification (Login API)
- Recherche d'identité : Récupération de l'enregistrement utilisateur basé sur le champ
mail.
- Validation d'empreinte : Comparaison du mot de passe en clair avec le hash stocké via
bcrypt.compare().
- Émission du Token : Génération d'un JSON Web Token (JWT) signé symétriquement avec
SECRET_KEY, contenant le role et l'id (Payload), avec une validité définie (2 heures).
app.post('/api/login', async (req, res) => {
const { mail, password } = req.body;
// Identification
const users = await db.all('SELECT * FROM Comptes WHERE mail = ?', [mail]);
if (users.length === 0) return res.status(401).json({ message: "Identifiants incorrects" });
// Validation cryptographique
const isValid = await bcrypt.compare(password, users[0].mot_de_passe);
if (!isValid) return res.status(401).json({ message: "Identifiants incorrects" });
// Création du JWT
const token = jwt.sign(
{ id: users[0].id, role: users[0].role, classe: users[0].classe },
SECRET_KEY,
{ expiresIn: '2h' }
);
res.json({ token, role: users[0].role, nom: users[0].nom, prenom: users[0].prenom });
});
React / frontend/src/App.jsx
Persistance côté Client
- Mise à jour d'état (State) : Hydratation des variables React (
token, role) pour mettre à jour l'interface de manière réactive.
- Stockage local (LocalStorage) : Enregistrement du JWT et des métadonnées dans le navigateur du client. Cela garantit le maintien de la session même après le rafraîchissement ou la fermeture de la page.
const saveAuthData = (data) => {
// 1. Mise à jour de l'état local (Interface réactive)
setToken(data.token);
setRole(data.role);
setPrenomUser(data.prenom);
setUserClasse(data.classe);
// 2. Persistance dans le navigateur
localStorage.setItem('jwtToken', data.token);
localStorage.setItem('userRole', data.role);
localStorage.setItem('userPrenom', data.prenom);
localStorage.setItem('userClasse', data.classe);
};
Node.js / backend/server.js
Sécurisation des Routes API (Middleware)
- Interception : Fonction exécutée avant chaque route protégée exigeant une authentification.
- Extraction : Analyse de l'en-tête HTTP
Authorization: Bearer <token>.
- Vérification d'intégrité : L'appel à
jwt.verify() s'assure que le token n'est pas expiré et que la signature correspond au serveur.
- Délégation : Injection de l'objet
user dans la requête (req) pour exploitation par le contrôleur final.
const verifierToken = (req, res, next) => {
// Extraction du format "Bearer [TOKEN]"
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.status(401).json({ message: "Accès refusé" });
// Vérification de la validité cryptographique
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.status(403).json({ message: "Token invalide" });
req.user = user; // Injection des données pour la route suivante
next(); // Autorisation de passage
});
};