Add JWT to enhance security
This commit is contained in:
@@ -4,8 +4,9 @@
|
|||||||
class Database {
|
class Database {
|
||||||
private $host = "127.0.0.1";
|
private $host = "127.0.0.1";
|
||||||
private $db_name = "VOTRE_BDD";
|
private $db_name = "VOTRE_BDD";
|
||||||
private $username = "VOTRE_USER";
|
private $username = "VOTRE_USER"; // N'utilisez par "root"
|
||||||
private $password = "VOTRE_MDP";
|
private $password = "VOTRE_MDP";
|
||||||
|
public $jwt_secret = "VOTRE_CLE_SECRETE_POUR_JWT"; // Une passphrase est préférable
|
||||||
public $conn;
|
public $conn;
|
||||||
|
|
||||||
// Récupérer la connexion
|
// Récupérer la connexion
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ require_once __DIR__ . '/../models/User.php';
|
|||||||
class UserController {
|
class UserController {
|
||||||
private $db;
|
private $db;
|
||||||
private $userModel;
|
private $userModel;
|
||||||
|
private $jwt_secret;
|
||||||
|
|
||||||
public function __construct($db) {
|
public function __construct($db, $jwt_secret = null) {
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
$this->userModel = new User($this->db);
|
$this->userModel = new User($this->db);
|
||||||
|
$this->jwt_secret = $jwt_secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- INTERCEPTE L'INSCRIPTION ---
|
// --- INTERCEPTE L'INSCRIPTION ---
|
||||||
@@ -44,14 +46,23 @@ class UserController {
|
|||||||
$result = $this->userModel->login($data['email'], $data['password']);
|
$result = $this->userModel->login($data['email'], $data['password']);
|
||||||
|
|
||||||
if ($result['success']) {
|
if ($result['success']) {
|
||||||
http_response_code(200); // 200 OK
|
require_once __DIR__ . '/../utils/JWT.php';
|
||||||
// TODO: Plus tard, on générera un token (JWT) ici pour sécuriser les sessions de l'API
|
|
||||||
} else {
|
|
||||||
http_response_code(401); // 401 Unauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// On prépare les infos à enfermer dans le token
|
||||||
|
$token_payload = ["user_id" => $result['user']['id']];
|
||||||
|
$token = JWT::generate($token_payload, $this->jwt_secret);
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
"success" => true,
|
||||||
|
"token" => $token, // Le client stockera ce token
|
||||||
|
"user" => $result['user']
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
http_response_code(401);
|
||||||
echo json_encode($result);
|
echo json_encode($result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- INTERCEPTE LA LIAISON DE COMPTES ---
|
// --- INTERCEPTE LA LIAISON DE COMPTES ---
|
||||||
public function link($data) {
|
public function link($data) {
|
||||||
|
|||||||
@@ -16,11 +16,14 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
|||||||
// --- CONFIGURATION ---
|
// --- CONFIGURATION ---
|
||||||
require_once __DIR__ . '/config/database.php';
|
require_once __DIR__ . '/config/database.php';
|
||||||
require_once __DIR__ . '/controllers/UserController.php';
|
require_once __DIR__ . '/controllers/UserController.php';
|
||||||
|
require_once __DIR__ . '/utils/JWT.php';
|
||||||
|
|
||||||
// Initialisation de la BDD et du contrôleur
|
// Initialisation de la BDD et du contrôleur
|
||||||
$database = new Database();
|
$database = new Database();
|
||||||
$db = $database->getConnection();
|
$db = $database->getConnection();
|
||||||
$userController = new UserController($db);
|
$jwt_secret = $database->jwt_secret;
|
||||||
|
|
||||||
|
$userController = new UserController($db, $jwt_secret);
|
||||||
|
|
||||||
// On récupère la route épurée (ex: si on tape /register, $route vaudra 'register')
|
// On récupère la route épurée (ex: si on tape /register, $route vaudra 'register')
|
||||||
$request_uri = explode('?', $_SERVER['REQUEST_URI'], 2)[0];
|
$request_uri = explode('?', $_SERVER['REQUEST_URI'], 2)[0];
|
||||||
@@ -30,52 +33,63 @@ $method = $_SERVER['REQUEST_METHOD'];
|
|||||||
// Récupération des données JSON reçues (ex: les credentials d'inscription)
|
// Récupération des données JSON reçues (ex: les credentials d'inscription)
|
||||||
$data = json_decode(file_get_contents('php://input'), true) ?? [];
|
$data = json_decode(file_get_contents('php://input'), true) ?? [];
|
||||||
|
|
||||||
|
// --- FONCTION DE SÉCURISATION DES ROUTES ---
|
||||||
|
function getAuthenticatedUserId($secret) {
|
||||||
|
$headers = apache_request_headers();
|
||||||
|
// On gère les différentes casses possibles pour le header Authorization
|
||||||
|
$authHeader = $headers['Authorization'] ?? $headers['authorization'] ?? null;
|
||||||
|
|
||||||
|
if (!$authHeader || !preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "Accès refusé. Token manquant."]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $matches[1];
|
||||||
|
$decoded = JWT::validate($token, $secret);
|
||||||
|
|
||||||
|
if (!$decoded) {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "Session expirée ou token invalide."]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decoded['user_id']; // Retourne le vrai user_id extrait du token
|
||||||
|
}
|
||||||
|
|
||||||
// --- ROUTEUR ---
|
// --- ROUTEUR ---
|
||||||
switch ($route) {
|
switch ($route) {
|
||||||
|
|
||||||
case 'register':
|
case 'register':
|
||||||
if ($method === 'POST') {
|
if ($method === 'POST') $userController->register($data);
|
||||||
$userController->register($data);
|
else http_response_code(405);
|
||||||
} else {
|
|
||||||
http_response_code(405);
|
|
||||||
echo json_encode(["error" => "Méthode non autorisée (POST requis)"]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'login':
|
case 'login':
|
||||||
if ($method === 'POST') {
|
if ($method === 'POST') $userController->login($data);
|
||||||
$userController->login($data);
|
else http_response_code(405);
|
||||||
} else {
|
|
||||||
http_response_code(405);
|
|
||||||
echo json_encode(["error" => "Méthode non autorisée (POST requis)"]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// --- TOUTES LES ROUTES CI-DESSOUS DEVIENNENT SÉCURISÉES ---
|
||||||
case 'link-partner':
|
case 'link-partner':
|
||||||
if ($method === 'POST') {
|
if ($method === 'POST') {
|
||||||
|
$data['user_id'] = getAuthenticatedUserId($jwt_secret); // Plus besoin d'envoyer user_id en clair, le token le donne !
|
||||||
$userController->link($data);
|
$userController->link($data);
|
||||||
} else {
|
} else { http_response_code(405); }
|
||||||
http_response_code(405);
|
|
||||||
echo json_encode(["error" => "Méthode non autorisée (POST requis)"]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'pairing-status':
|
case 'pairing-status':
|
||||||
if ($method === 'POST') { // On utilise POST temporairement pour lire le user_id dans le JSON
|
if ($method === 'POST') {
|
||||||
|
$data['user_id'] = getAuthenticatedUserId($jwt_secret);
|
||||||
$userController->pairingStatus($data);
|
$userController->pairingStatus($data);
|
||||||
} else {
|
} else { http_response_code(405); }
|
||||||
http_response_code(405);
|
|
||||||
echo json_encode(["error" => "Méthode non autorisée (POST requis)"]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'unlink-partner':
|
case 'unlink-partner':
|
||||||
if ($method === 'POST') {
|
if ($method === 'POST') {
|
||||||
|
$data['user_id'] = getAuthenticatedUserId($jwt_secret);
|
||||||
$userController->unlink($data);
|
$userController->unlink($data);
|
||||||
} else {
|
} else { http_response_code(405); }
|
||||||
http_response_code(405);
|
|
||||||
echo json_encode(["error" => "Méthode non autorisée (POST requis)"]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
// utils/JWT.php
|
||||||
|
|
||||||
|
class JWT {
|
||||||
|
// Encode en Base64 utilisable dans une URL
|
||||||
|
private static function base64UrlEncode($text) {
|
||||||
|
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($text));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Décode le Base64 d'URL
|
||||||
|
private static function base64UrlDecode($text) {
|
||||||
|
$base64 = str_replace(['-', '_'], ['+', '/'], $text);
|
||||||
|
return base64_decode($base64 . substr('===', (strlen($base64) % 4) ?: 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. GÉNÉRER LE TOKEN
|
||||||
|
public static function generate($payload, $secret) {
|
||||||
|
$header = json_encode(['alg' => 'HS256', 'typ' => 'JWT']);
|
||||||
|
|
||||||
|
// On ajoute une date d'expiration (ex: valide 30 jours)
|
||||||
|
$payload['exp'] = time() + (30 * 24 * 60 * 60);
|
||||||
|
$payload_json = json_encode($payload);
|
||||||
|
|
||||||
|
$base64UrlHeader = self::base64UrlEncode($header);
|
||||||
|
$base64UrlPayload = self::base64UrlEncode($payload_json);
|
||||||
|
|
||||||
|
// Signature HMAC SHA256
|
||||||
|
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secret, true);
|
||||||
|
$base64UrlSignature = self::base64UrlEncode($signature);
|
||||||
|
|
||||||
|
return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. VÉRIFIER LE TOKEN
|
||||||
|
public static function validate($token, $secret) {
|
||||||
|
$part = explode('.', $token);
|
||||||
|
if (count($part) !== 3) return false;
|
||||||
|
|
||||||
|
list($header, $payload, $signature) = $part;
|
||||||
|
|
||||||
|
// On refait la signature pour vérifier si elle correspond
|
||||||
|
$valid_signature = hash_hmac('sha256', $header . "." . $payload, $secret, true);
|
||||||
|
$valid_base64UrlSignature = self::base64UrlEncode($valid_signature);
|
||||||
|
|
||||||
|
if ($signature !== $valid_base64UrlSignature) return false;
|
||||||
|
|
||||||
|
$payload_data = json_encode(json_decode(self::base64UrlDecode($payload), true));
|
||||||
|
$data = json_decode($payload_data, true);
|
||||||
|
|
||||||
|
// Vérification de la date d'expiration
|
||||||
|
if (isset($data['exp']) && $data['exp'] < time()) return false;
|
||||||
|
|
||||||
|
return $data; // Renvoie les données (user_id) si tout est OK
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user