Qu’est-ce que JWT ? Cet article vous amènera à comprendre JWT, à présenter l'application de JWT dans le nœud, ainsi que les avantages et les inconvénients de JWT. J'espère qu'il sera utile à tout le monde !
JWT est l'abréviation de JSON Web Token , qui est une solution d'authentification dans l'environnement d'application réseau. Dans le mécanisme d'authentification traditionnel, il ne s'agit que des étapes suivantes :
1. L'utilisateur envoie le mot de passe du compte au serveur ; 2. Une fois que le serveur a vérifié le mot de passe du compte, il enregistrera certaines informations relatives à l'utilisateur, les rôles d'utilisateur ou le délai d'expiration, etc. dans la session en cours ; 3. Le serveur donne à l'utilisateur un session_id et l'écrit dans le cookie de l'utilisateur ou le client l'enregistre localement ; 4. Chaque fois que l'utilisateur demande un service, il doit fournir ce session_id, peut-être via des cookies ou d'autres méthodes ; 5. Une fois que le serveur l'a reçu, il retourne à la base de données pour interroger le session_id actuel et vérifie si l'utilisateur a l'autorisation ;
Un avantage de ce modèle est que le serveur peut mettre fin aux autorisations de l'utilisateur à tout moment et accéder à la base de données pour modifier ou supprimer les informations de session de l'utilisateur actuel. Mais il existe également un inconvénient : s'il s'agit d'un cluster de serveurs, toutes les machines doivent partager les informations de session pour garantir que chaque serveur puisse obtenir les mêmes informations de stockage de session. Bien que ces problèmes puissent être résolus, la quantité de travail est énorme.
L'avantage de la solution JWT est que ces informations ne sont pas enregistrées. Les données du token sont enregistrées sur le client. Chaque fois qu'une demande est acceptée, il suffit de la vérifier.
Parlons brièvement du principe de JWT. En effet, lorsque le client envoie une demande d'authentification, le serveur va générer un objet JSON après avoir authentifié l'utilisateur, qui comprend probablement des informations telles que « qui êtes-vous, que faites-vous, etc. ., délai d'expiration " , l'important est qu'il doit y avoir un délai d'expiration ; le format général est :
{ nom d'utilisateur : "voleur de chaîne euh", Rôle : "World Code Farmer", endTime : « 20 mai 2022 » }
Mais il ne vous sera pas transmis de manière aussi superficielle. Il sera signé et transmis via un algorithme de signature réversible basé sur l'algorithme de signature spécifié et certaines informations sur la charge utile que vous avez soumise. J'utiliserai une image pour représenter le format général. :
Comme le montre l'image, les informations renvoyées sont grossièrement divisées en trois parties. Le côté gauche est le résultat après signature, qui est le résultat renvoyé au client. Le côté droit est également le code source décodé. séparés respectivement par des « points ». Il existe une correspondance biunivoque entre les trois couleurs rouge, violet et cyan :
La première partie rouge est l'en-tête. L'en-tête spécifie principalement la méthode. L'algorithme de signature dans l'image ( HS256 par défaut ) est HMAC avec SHA-256. Il s'agit d'un algorithme symétrique partagé entre les deux parties. l'identifiant du champ est de type JWT ;
La deuxième partie violette, payload, est un objet JSON, qui correspond aux données réelles à transmettre. Sept champs officiels peuvent être utilisés :
iss (émetteur) : émetteur
exp (heure d'expiration) : heure d'expiration
sous (sujet):sujet
aud (audience) : audience
nbf (Pas avant) : Temps effectif
iat (Issued At) : heure d'émission
jti (ID JWT) : numéro
En plus de ces champs, vous pouvez également créer des champs personnalisés étant donné que JWT n'est pas chiffré par défaut, essayez de faire attention à ne pas utiliser certaines données sensibles lorsque vous l'utilisez.
La troisième partie est la signature Signature
. Cette partie est une clé secrète que vous avez spécifiée et qui existe uniquement sur le serveur, puis qui utilise l'algorithme spécifié dans l'en-tête pour signer via la méthode de signature suivante.
Expérimentons l'utilisation spécifique ci-dessous :
Étape 1 : Nous devons créer un projet nodejs ; initialiser un projet via npm init -y
; puis nous devons installer les dépendances, notamment express
, jsonwebtoken
et nodemon
:
$ npm j'exprime jsonwebtoken nodemon
Ajoutez ensuite la commande nodemon app.js
dans le champ scripts
de package.json
:
"scripts": { "start": "nodemon app.js" },
Étape 2 : initialisez l'application de nœud et créez le fichier app.js dans le répertoire racine ;
// app.js const express = require("express"); const app = express(); app.use(express.json()); app.écouter(3000, () => { console.log(3000 + "écoute..."); // Écoute le port 3000});
Étape 3 : Introduisez jsonwebtoken
et créez la clé privée de l'interface et du serveur ;
// app.js //... const jwt = require("jsonwebtoken"); const jwtKey = "~!@#$%^&*()+,"; //...
jwtKey
ici est notre clé privée personnalisée qui est uniquement enregistrée sur le serveur. Après cela, nous avons commencé à écrire une interface /login pour la connexion, et avons créé une base de données de simulation locale pour la vérification, et l'avons réalisée via la méthode jwt.sign
. Vérifier la signature :
// app.js base de données const = { nom d'utilisateur : "nom d'utilisateur", mot de passe : "mot de passe", } ; app.post("/login", (req, res) => { const { nom d'utilisateur, mot de passe } = req.body; if (nom d'utilisateur === base de données.nom d'utilisateur && mot de passe === base de données.mot de passe) { jwt.sign( { nom d'utilisateur, }, jwtClé, { expire dans : "30 S", }, (_, jeton) => { res.json({ nom d'utilisateur, message : "Connexion réussie", jeton, }); } ); } });
Dans le code ci-dessus, nous avons créé database
pour simuler la création d'une base de données locale de comptes et de mots de passe pour vérifier la connexion ; puis nous avons établi une interface post
/login
. Après avoir vérifié que le compte et le mot de passe correspondent parfaitement, nous l'avons importé via jsonwebtoken
package. Utilisez la méthode sign
sous l’objet jwt
pour signer. Cette méthode a trois signatures d’interface :
signe de fonction d'exportation ( charge utile : chaîne | Objet Buffer | secretOuPrivateKey : Secret, options ? : Options de signe, ): chaîne; signe de fonction d'exportation ( charge utile : chaîne | Objet Buffer | secretOuPrivateKey : Secret, rappel : SignCallback, ): vide; signe de fonction d'exportation ( charge utile : chaîne | Objet Buffer | secretOuPrivateKey : Secret, options : Options de signe, rappel : SignCallback, ): vide;
La méthode de surcharge de fonctions est utilisée ici pour implémenter l'interface.Nous implémenterons ici la dernière signature d'interface.Le premier paramètre peut être un type d'objet personnalisé, un type Buffer
, ou directement un type object
string
. et personnalise certains champs, car JWT signera également ces données lors de la signature. Cependant, il convient de noter que vous devez essayer de ne pas utiliser de données sensibles ici car JWT n'est pas chiffré par défaut. Le noyau est la signature , qui garantit que les données. n'a pas été falsifié et le processus de vérification de la signature est appelé vérification .
Bien entendu, vous pouvez également crypter le Token original puis le transmettre ;
Le deuxième paramètre : est la clé secrète que nous enregistrons sur le serveur pour la signature. Habituellement en mode client-serveur, JWS utilise l'algorithme HS256 fourni par JWA plus une clé. Cette méthode repose strictement sur la clé. plusieurs services peuvent avoir besoin de vérifier JWT. Si la clé est enregistrée dans chaque service, la sécurité sera considérablement réduite. Vous devez savoir qu'une fois la clé divulguée, n'importe qui peut falsifier JWT à volonté.
Le troisième paramètre : est l'option de signature SignOptions
, la signature de l'interface :
interface d'exportation SignOptions { algorithme ? : Algorithme | non défini ; ID clé ? : chaîne | non défini ; expiresIn?: chaîne numéro | non défini ; /** exprimé en secondes ou une chaîne décrivant un intervalle de temps [zeit/ms](https://github.com/zeit/ms.js Par exemple : 60, "2 jours", "10h", "7j". */ notBefore ? : chaîne numéro | non défini ; public ? : chaîne | chaîne[] | non défini ; sujet ? : chaîne | non défini ; émetteur ? : chaîne | non défini ; jwtid?: chaîne | non défini ; mutatePayload ? : booléen | non défini ; noTimestamp ? : booléen | non défini ; en-tête ? : JwtHeader | non défini ; encodage ? : chaîne | non défini ; }
Ici, nous utilisons le champ expiresIn
pour spécifier le temps d'attente. Veuillez vous référer à ce document pour les méthodes d'utilisation ;
Le quatrième paramètre est un rappel. Le deuxième paramètre du rappel est token
que nous avons généré via la signature. Enfin, ce token
est renvoyé au front-end afin qu'il puisse être stocké localement sur le front-end et amené au serveur pour vérification. à chaque demande.
Vérifions ensuite cette interface : j'ai installé le plug-in client REST dans vscode, puis j'ai créé un fichier request.http
dans le répertoire racine et j'ai écrit les informations demandées dans le fichier :
POST http://localhost:3000/login type de contenu : application/json { "nom d'utilisateur": "nom d'utilisateur", "mot de passe": "mot de passe" }
Exécutez ensuite la commande npm run start
sur la ligne de commande pour démarrer le service, puis cliquez sur le bouton Send Request
au-dessus du fichier requset.http
pour envoyer la demande :
Une fois la demande réussie, vous verrez un message de réponse comme celui-ci :
Le champ token
est token
généré par notre JWT ;
Vérifions si ce token
est valide. Nous écrivons une interface après la connexion :
app.get("/afterlogin", (req, res) => { const { en-têtes } = req; const token = en-têtes["autorisation"].split(" ")[1]; //Mettez le token dans le champ d'autorisation de l'en-tête jwt.verify(token, jwtKey, (err, payload) => { si (erreur) renvoie res.sendStatus(403); res.json({ message : "Authentification réussie", charge utile }); }); });
Dans ce code, token
précédemment généré via JWT est obtenu en obtenant token
dans le champ authorization
de l'en-tête de la requête. Vérifiez ensuite si le token
est valide en appelant jwt.verify
. Cette méthode a trois paramètres :
// Il existe quatre signatures d'interface, vous pouvez vérifier vous-même la documentation fonction d'exportation vérifier ( jeton : chaîne, //Jeton qui doit être vérifié secretOuPublicKey : Secret | GetPublicKeyOrSecret, // La clé de signature définie sur le rappel du serveur ? : VerifyCallback<JwtPayload string>, // Rappel pour obtenir le résultat des informations de vérification) : void;
Ensuite, nous copions token
auquel nous venons de répondre dans l'en-tête de la requête :
### OBTENIR http://localhost:3000/afterlogin autorisation : Porteur eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNjUyNzg5NzA3LCJleHAiOjE2NTI3ODk3Mzd9.s9fk3YLhxTUcpUgCfIK4xQ N58 Hk_XEP5y9GM9A8jBbY
L'authentification Bearer précédente est la méthode d'authentification standard dans le protocole http.
Cliquez également sur Send Request
et lorsque vous voyez la réponse dans l'image ci-dessous, cela signifie que la réponse a réussi :
En fait, voici quelques utilisations simples de JWT. Parlons ensuite des avantages et des inconvénients de JWT lui-même.
L'espace de stockage occupé par JWT n'est en fait pas petit. Si nous devons signer trop d'informations, le jeton risque de dépasser la limite de longueur du cookie. Par exemple, comparez ces deux images :
Évidemment, à mesure que la quantité d’informations dans la charge utile augmente, la longueur du jeton augmentera également ;
Sécurité, en effet, si token
prend trop de place, l'espace de stockage maximum Cookie
n'est que de 4 Ko. Le front-end peut être stocké dans un stockage local tel que localStorage
, mais cela posera un problème s'il n'est pas placé. dans le cookie, la sécurité sera considérablement réduite. Il y aura un risque de l'obtenir via le script js, ce qui signifie que n'importe quel hacker pourra en faire n'importe quoi ;
Rapidité inflexible. En fait, un certain aspect de JWT est que le token
utilisateur n'a pas besoin d'être stocké de manière persistante, au lieu de cela, token
est effectivement vérifié à l'aide de la vérification du serveur, si. le délai d'expiration est modifié, token
sera falsifié. Puisqu'il n'y a aucun moyen de stocker et de modifier manuellement la date d'expiration, il est difficile de supprimer le token
immédiatement. Si l'utilisateur se connecte deux fois et que deux token
sont générés, alors. En principe, deux token
seront générés et tous valides ;
Ce qui précède parle principalement de quelques points :
Le principe de JWT est principalement d'utiliser la clé privée du serveur pour communiquer avec token
généré par la signature JSON ;
Il présente également la composition des données internes de JWT, qui est utilisée par Header pour spécifier l'algorithme et le type de signature, la charge utile pour transmettre les données JSON et Signature pour exécuter un algorithme de signature sur les données et empêcher toute falsification ;
Une introduction détaillée est donnée sur la façon d'utiliser JWT via nodejs, d'effectuer la signature des données via la méthode sign
et d'effectuer la vérification de la signature via la méthode verify
;
Certains inconvénients de JWT sont également introduits :
La première est que l’espace de stockage augmente à mesure que la quantité de données de signature augmente ;
Ensuite, il y a la sécurité. Si l'espace de stockage est trop important, il ne sera pas stocké dans Cookie
avec un niveau de sécurité relativement élevé, ce qui entraînera l'obtention du script à volonté ;
Ensuite, il y a l'actualité, qui ne peut pas contrôler de manière flexible l'actualité des token
;
Il s'agit du code source de démonstration de nodejs ci-dessus pour référence ;