jwt.class.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /**
  3. * Classe jwt
  4. *
  5. * Cette classe gère la génération, la validation et la manipulation des JSON Web Tokens (JWT).
  6. */
  7. class jwt
  8. {
  9. /**
  10. * @var string|null $jwtToken Le jeton JWT actuellement utilisé.
  11. */
  12. private static $jwtToken;
  13. /**
  14. * @var string $jwtSecret Clé secrète utilisée pour signer les tokens.
  15. */
  16. private static $jwtSecret = JWT_PRIVATE_KEY;
  17. /**
  18. * @var string $jwtAlgorithm Algorithme utilisé pour signer les JWT (par défaut : HS256).
  19. */
  20. private static $jwtAlgorithm = "HS256";
  21. /**
  22. * Initialise les configurations pour l'authentification.
  23. *
  24. * @param string $loginUrl URL de connexion.
  25. * @param string $apiBaseUrl URL de base de l'API.
  26. * @param string $email Adresse e-mail de l'utilisateur.
  27. * @param string $password Mot de passe de l'utilisateur.
  28. */
  29. public static function init($loginUrl, $apiBaseUrl, $email, $password)
  30. {
  31. // Le JWT sera stocké dans cette propriété statique
  32. self::$jwtToken = null;
  33. }
  34. /**
  35. * Vérifie si une session JWT est valide.
  36. *
  37. * @return string JSON indiquant si l'utilisateur est authentifié.
  38. */
  39. public static function checkSession()
  40. {
  41. // Vérifie si le JWT existe et n'est pas expiré
  42. if (self::$jwtToken && self::validateToken(self::$jwtToken)) {
  43. return json_encode(['authenticated' => true, 'token' => self::$jwtToken]);
  44. } else {
  45. return json_encode(['authenticated' => false]);
  46. }
  47. }
  48. /**
  49. * Authentifie l'utilisateur et génère un JWT.
  50. *
  51. * @param array $_input Données d'entrée pour l'authentification.
  52. * @return array|false Données utilisateur avec le token ou FALSE en cas d'échec.
  53. */
  54. public static function authenticate(array $_input)
  55. {
  56. $user = user::authenticator($_input);
  57. if ($user["status"] == "success") {
  58. // Générer le JWT
  59. $user["token"] = self::generateToken($user);
  60. self::$jwtToken = $user["token"];
  61. return $user;
  62. } else {
  63. return FALSE;
  64. }
  65. }
  66. /**
  67. * Effectue une requête API authentifiée avec le JWT.
  68. *
  69. * @param string $endpoint Point de terminaison de l'API.
  70. * @param string $method Méthode HTTP (GET, POST, PUT, DELETE).
  71. * @param array $data Données à envoyer dans la requête.
  72. * @return array Réponse de l'API.
  73. * @throws Exception Si le JWT est invalide ou expiré.
  74. */
  75. public static function makeAuthenticatedRequest($endpoint, $method = 'GET', $data = [])
  76. {
  77. if (!self::$jwtToken) {
  78. throw new Exception('Aucun jeton JWT disponible. Veuillez vous authentifier.');
  79. }
  80. // Vérification du token avant d'effectuer une requête
  81. if (!self::validateToken(self::$jwtToken)) {
  82. throw new Exception('Jeton JWT invalide ou expiré. Veuillez vous authentifier à nouveau.');
  83. }
  84. $ch = curl_init();
  85. $url = DOMAIN_API . $endpoint;
  86. curl_setopt($ch, CURLOPT_URL, $url . "/");
  87. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  88. // Ajouter le JWT dans l'en-tête d'autorisation
  89. curl_setopt($ch, CURLOPT_HTTPHEADER, [
  90. 'Authorization: Bearer ' . self::$jwtToken,
  91. 'Content-Type: application/json'
  92. ]);
  93. // Configuration des méthodes GET/POST/PUT/DELETE
  94. if ($method === 'POST') {
  95. curl_setopt($ch, CURLOPT_POST, true);
  96. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  97. } elseif ($method === 'PUT') {
  98. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
  99. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  100. } elseif ($method === 'DELETE') {
  101. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
  102. }
  103. $response = curl_exec($ch);
  104. curl_close($ch);
  105. if ($response === false) {
  106. throw new Exception('Erreur lors de la requête API.');
  107. }
  108. return json_decode($response, true);
  109. }
  110. /**
  111. * Rafraîchit un JWT expiré.
  112. *
  113. * @param string $expiredToken Le token expiré.
  114. * @return string|null Nouveau token ou null si échec.
  115. */
  116. public static function refreshToken(string $expiredToken)
  117. {
  118. // Décoder le token sans vérifier son expiration
  119. $tokenParts = explode('.', $expiredToken);
  120. if (count($tokenParts) !== 3) {
  121. return null; // Token incorrect
  122. }
  123. $header = $tokenParts[0];
  124. $payload = $tokenParts[1];
  125. $signatureProvided = $tokenParts[2];
  126. // Vérifier la signature
  127. $signatureValid = hash_hmac('sha256', $header . '.' . $payload, self::$jwtSecret, true);
  128. $base64UrlSignature = self::base64UrlEncode($signatureValid);
  129. if ($base64UrlSignature !== $signatureProvided) {
  130. return null; // Signature incorrecte
  131. }
  132. // Décoder le payload
  133. $payloadDecoded = json_decode(self::base64UrlDecode($payload), true);
  134. // Vérifier si le token est expiré
  135. if (isset($payloadDecoded['exp']) && time() < $payloadDecoded['exp']) {
  136. return $expiredToken; // Le token n'est pas encore expiré, inutile de le rafraîchir
  137. }
  138. // Le token est expiré, régénérer un nouveau token avec les mêmes données mais une nouvelle expiration
  139. unset($payloadDecoded['exp']); // On enlève l'expiration actuelle
  140. $new = self::generateToken($payloadDecoded); // Générer un nouveau token
  141. user::updateJWTbyMd5(md5($expiredToken), $new);
  142. return $new;
  143. }
  144. /**
  145. * Révoque le JWT actuel (déconnexion).
  146. */
  147. public static function logout()
  148. {
  149. self::$jwtToken = null; // Supprimer le JWT
  150. }
  151. /**
  152. * Génère un JWT avec un payload donné.
  153. *
  154. * @param array $payload Données à inclure dans le token.
  155. * @return string Le JWT généré.
  156. */
  157. private static function generateToken($payload)
  158. {
  159. $header = json_encode([
  160. 'typ' => 'JWT',
  161. 'alg' => self::$jwtAlgorithm
  162. ]);
  163. $base64UrlHeader = self::base64UrlEncode($header);
  164. $base64UrlPayload = self::base64UrlEncode(json_encode($payload));
  165. // Créer la signature
  166. $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, self::$jwtSecret, true);
  167. $base64UrlSignature = self::base64UrlEncode($signature);
  168. // Retourner le token complet
  169. return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
  170. }
  171. /**
  172. * Valide un JWT donné.
  173. *
  174. * @param string $token Le token à valider.
  175. * @return bool TRUE si le token est valide, FALSE sinon.
  176. */
  177. public static function validateToken(string $token)
  178. {
  179. $baseJWT = user::getInfosByJWT($token);
  180. if($baseJWT == FALSE){
  181. return false; // Token en base expirée
  182. }
  183. $tokenParts = explode('.', $token);
  184. if (count($tokenParts) !== 3) {
  185. return false; // Token incorrect
  186. }
  187. $header = $tokenParts[0];
  188. $payload = $tokenParts[1];
  189. $signatureProvided = $tokenParts[2];
  190. // Vérifier la signature
  191. $signatureValid = hash_hmac('sha256', $header . '.' . $payload, self::$jwtSecret, true);
  192. $base64UrlSignature = self::base64UrlEncode($signatureValid);
  193. if ($base64UrlSignature !== $signatureProvided) {
  194. return false; // Signature incorrecte
  195. }
  196. // Décoder le payload
  197. $payloadDecoded = json_decode(self::base64UrlDecode($payload), true);
  198. // Vérifier l'expiration du token
  199. if (isset($payloadDecoded['exp']) && time() >= $payloadDecoded['exp']) {
  200. return false; // Token expiré
  201. }
  202. return true; // Token valide
  203. }
  204. /**
  205. * Encode des données en Base64 URL.
  206. *
  207. * @param string $data Les données à encoder.
  208. * @return string Les données encodées.
  209. */
  210. private static function base64UrlEncode($data)
  211. {
  212. return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
  213. }
  214. /**
  215. * Décode des données en Base64 URL.
  216. *
  217. * @param string $data Les données à décoder.
  218. * @return string Les données décodées.
  219. */
  220. private static function base64UrlDecode($data)
  221. {
  222. return base64_decode(strtr($data, '-_', '+/'));
  223. }
  224. }