Maison > interface Web > js tutoriel > le corps du texte

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

青灯夜游
Libérer: 2023-01-04 21:00:18
avant
2392 Les gens l'ont consulté

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 !

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

Qu'est-ce que JWT

JWT est l'abréviation de JSON Web Token, qui est une solution d'authentification dans l'environnement des applications réseau. Dans le mécanisme d'authentification traditionnel, il n'y a rien de plus que quelques étapes :

1. 用户将账号密码发送到服务器;

2. 服务器通过验证账号密码后,会在当前session中保存一些用户相关的信息,用户角色或者过期时间等等;

3. 服务器给用户一个session_id, 写入用户的Cookie或者客户端自行保存在本地;

4. 用户每次请求服务,都需要带上这个session_id,或许会通过Cookie,或者其他的方式;

5. 服务器接收到后,回去数据库查询当前的session_id,校验该用户是否有权限;
Copier après la connexion

L'un des avantages 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. Même si ces problèmes peuvent ê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. [Tutoriels associés recommandés : Tutoriel vidéo Nodejs, Enseignement de la programmation]

Principe de JWT

Parlons brièvement du principe de JWT En fait, lorsque le client envoie une demande d'authentification, le serveur génère. après avoir authentifié l'utilisateur. Un objet JSON comprend probablement des informations telles que "Qui êtes-vous, que faites-vous, etc., Heure d'expiration".

{
    username: "贼烦字符串er",
    role: "世代码农",
    endTime: "2022年5月20日"
}
Copier après la connexion

Mais il ne sera pas utilisé comme ça. Il vous sera transmis de manière 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. une image pour représenter le format général :

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

L'image peut être utilisée On voit que 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é. Les trois parties sont séparées par des "points" et sont séparées par du rouge et les trois couleurs violet et bleu correspondent une à une :

  • 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. C'est un algorithme symétrique, une seule clé est partagée entre les deux parties et le champ typ est marqué comme type JWT ;

  • La charge utile de la deuxième partie violette est un objet JSON, qui correspond aux données réelles à transmettre. Il y en a sept. Les champs officiels peuvent être utilisés :

      iss (émetteur) : émetteur
    • exp (heure d'expiration) : heure d'expiration
    • sub (sujet) : sujet
    • aud (audience) : audience
    • nbf (Pas avant) : heure d'effet
    • iat (émis à) : heure d'émission
    • jti (JWT ID) : 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, il est utilisé. Essayez de faire attention à ne pas utiliser certaines données sensibles.

  • La troisième partie est la signature Signature Cette partie est une clé secrète spécifiée par vous-même et n'existe que sur le serveur, puis utilise l'algorithme spécifié dans l'en-tête pour signer via la signature suivante. méthode.

    Signature签名,这一部分,是由你自己指定且只有服务器存在的秘钥,然后使用头部指定的算法通过下面的签名方法进行签名。

JWT的简单使用

下面我们来感受一下具体的使用:

第一步:我们需要搭建一个node的项目;通过npm init -y初始化一个项目;之后我们需要安装依赖,分别按状expressjsonwebtokennodemon三个依赖:

$ npm i express jsonwebtoken nodemon
Copier après la connexion

之后在package.json中的scripts字段中添加nodemon app.js命令:

"scripts": {
    "start": "nodemon app.js"
},
Copier après la connexion

第二步:初始化一下node应用,在根目录下创建app.js文件;

// app.js

const express = require("express");
const app = express();

app.use(express.json());

app.listen(3000, () => {
  console.log(3000 + " listening..."); // 监听3000端口
});
Copier après la connexion

第三步:引入jsonwebtoken依赖,并且创建接口和服务器的私钥;

// app.js

//...
const jwt = require("jsonwebtoken");

const jwtKey = "~!@#$%^&*()+,";
// ...
Copier après la connexion

这里面的jwtKey是我们自定义保存仅限保存在服务器中的私钥,之后我们开始写一个 /login 接口,用来登录,并且创建本地的模拟数据库用来校验,并通过jwt.sign方法进行校验签名:

// app.js
const database = {
  username: "username",
  password: "password",
};

app.post("/login", (req, res) => {
  const { username, password } = req.body;
  if (username === database.username && password === database.password) {
    jwt.sign(
      {
        username,
      },
      jwtKey,
      {
        expiresIn: "30S",
      },
      (_, token) => {
        res.json({
          username,
          message: "登陆成功",
          token,
        });
      }
    );
  }
});
Copier après la connexion

上面代码中我们创建了database变量来模拟创建了本地的账号密码数据库,用来校验登陆;接下来建立了一个/loginpost接口,在校验账号密码完全匹配之后,我们通过jsonwebtoken包导入的jwt对象下的人sign

🎜🎜 Utilisation simple de JWT🎜🎜🎜 Expérimentons l'utilisation spécifique : 🎜🎜Étape 1 : Nous devons construire un projet 🎜node🎜 ; l'initialiser via npm init -y Un projet ; ensuite il faut installer les dépendances, respectivement express, jsonwebtoken et nodemon : 🎜
export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    options?: SignOptions,
): string;

export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    callback: SignCallback,
): void;

export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    options: SignOptions,
    callback: SignCallback,
): void;
Copier après la connexion
Copier après la connexion
🎜 puis Ajouter le <code>nodemon app.js dans le champ scripts de package.json : 🎜
export interface SignOptions {
    algorithm?: Algorithm | undefined;
    keyid?: string | undefined;
    expiresIn?: string | number | undefined;
    /** expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms.js).  Eg: 60, "2 days", "10h", "7d" */
    notBefore?: string | number | undefined;
    audience?: string | string[] | undefined;
    subject?: string | undefined;
    issuer?: string | undefined;
    jwtid?: string | undefined;
    mutatePayload?: boolean | undefined;
    noTimestamp?: boolean | undefined;
    header?: JwtHeader | undefined;
    encoding?: string | undefined;
}
Copier après la connexion
Copier après la connexion
🎜Étape 2 : Initialisez l'application de nœud et créez-la dans le fichier app.js du répertoire racine ; 🎜
POST http://localhost:3000/login
content-type: application/json

{
  "username": "username",
  "password": "password"
}
Copier après la connexion
Copier après la connexion
🎜Étape 3 : Introduisez la dépendance jsonwebtoken, et créez la clé privée de l'interface et du serveur ; 🎜
app.get("/afterlogin", (req, res) => {
  const { headers } = req;
  
  const token = headers["authorization"].split(" ")[1];
  // 将token放在header的authorization字段中
  jwt.verify(token, jwtKey, (err, payload) => {
    if (err) return res.sendStatus(403);
    res.json({ message: "认证成功", payload });
  });
});
Copier après la connexion
Copier après la connexion
🎜La jwtKey ici est notre coutume Seules les clés privées enregistrées sur le serveur peut être enregistré. Ensuite, 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 vérifiée via la méthode jwt.sign : 🎜
// 有四个接口签名,可以自行查文档

export function verify(
    token: string,
    // 需要检验的token
    secretOrPublicKey: Secret | GetPublicKeyOrSecret,
    // 定义在服务器的签名秘钥
    callback?: VerifyCallback<JwtPayload | string>,
    // 获取校验信息结果的回调
): void;
Copier après la connexion
Copier après la connexion
🎜Dans le code ci-dessus, nous avons créé la variable 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 créé un /login</code > ; code>post, après avoir vérifié que le compte et le mot de passe correspondent parfaitement, nous utilisons le package jsonwebtoken pour importer le signe de la personne sous l'objet <code>jwt pour signer, cette méthode possède trois signatures d'interface : 🎜
export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    options?: SignOptions,
): string;

export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    callback: SignCallback,
): void;

export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    options: SignOptions,
    callback: SignCallback,
): void;
Copier après la connexion
Copier après la connexion

这里用到了函数重载的方式实现接口,我们这里将实现最后一个接口签名,第一个参数可以是一个自定义的对象类型,也可以是一个Buffer类型,还可以直接是一个string类型,我们的源码使用了object类型,自定义了一些字段,因为jwt在进行签名是也会对这些数据一并进行签名,但是值得注意的是,这里尽量不要使用敏感数据,因为JWT默认是不加密的,它的核心就是签名,保证数据未被篡改,而检查签名的过程就叫做验证

当然你也可以对原始Token进行加密后传输;

第二个参数:是我们保存在服务器用来签名的秘钥,通常在客户端-服务端模式中,JWS 使用 JWA 提供的 HS256 算法加上一个密钥即可,这种方式严格依赖密钥,但在分布式场景,可能多个服务都需要验证JWT,若要在每个服务里面都保存密钥,那么安全性将会大打折扣,要知道,密钥一旦泄露,任何人都可以随意伪造JWT。

第三个参数:是签名的选项SignOptions,接口的签名:

export interface SignOptions {
    algorithm?: Algorithm | undefined;
    keyid?: string | undefined;
    expiresIn?: string | number | undefined;
    /** expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms.js).  Eg: 60, "2 days", "10h", "7d" */
    notBefore?: string | number | undefined;
    audience?: string | string[] | undefined;
    subject?: string | undefined;
    issuer?: string | undefined;
    jwtid?: string | undefined;
    mutatePayload?: boolean | undefined;
    noTimestamp?: boolean | undefined;
    header?: JwtHeader | undefined;
    encoding?: string | undefined;
}
Copier après la connexion
Copier après la connexion

这里我们用的是expiresIn字段,指定了时效时间,使用方法参考这个文档;

第四个参数是一个回调,回调的第二个参数就是我们通过签名生成的token,最后将这个token返回给前端,以便存储到前端本地每次请求是带上到服务端进行验证。

接下来,我们来验证一下这个接口: 我是在vscode安装的REST Client插件,之后在根目录创建一个request.http的文件,文件内写上请求的信息:

POST http://localhost:3000/login
content-type: application/json

{
  "username": "username",
  "password": "password"
}
Copier après la connexion
Copier après la connexion

之后在命令行执行npm run start命令启动服务,之后在requset.http文件上方点击Send Request按钮,发送请求:

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

请求成功后,会看到这样的响应报文:

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

token字段就是我们JWT生成的token;

下面来验证一下这个token是否有效,我们在写一个登录过后的接口:

app.get("/afterlogin", (req, res) => {
  const { headers } = req;
  
  const token = headers["authorization"].split(" ")[1];
  // 将token放在header的authorization字段中
  jwt.verify(token, jwtKey, (err, payload) => {
    if (err) return res.sendStatus(403);
    res.json({ message: "认证成功", payload });
  });
});
Copier après la connexion
Copier après la connexion

这段代码中,通过获取请求头中的authorization字段中的token进行获取之前通过JWT生成的token。 之后通过调用jwt.verify校验方法校验这个token是否有效,这个方法分别有三个参数:

// 有四个接口签名,可以自行查文档

export function verify(
    token: string,
    // 需要检验的token
    secretOrPublicKey: Secret | GetPublicKeyOrSecret,
    // 定义在服务器的签名秘钥
    callback?: VerifyCallback<JwtPayload | string>,
    // 获取校验信息结果的回调
): void;
Copier après la connexion
Copier après la connexion

接下来我们把刚才响应的token复制到请求头中:

###
GET http://localhost:3000/afterlogin
authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNjUyNzg5NzA3LCJleHAiOjE2NTI3ODk3Mzd9.s9fk3YLhxTUcpUgCfIK4xQN58Hk_XEP5y9GM9A8jBbY
Copier après la connexion

前面的Bearer认证, 是http协议中的标准认证方式

同样点击Send Request当看到下面图片的响应,就意味着响应成功:

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

其实以上就是JWT的一些简单的用法,接下来再说一下JWT本身存在的优缺点.

JWT的不足

  • JWT占用的存储空间其实并不小,如果我们需要签名做过多的信息,那么token很可能会超出cookie的长度限制,例如对比一下这两张图片:

Une brève analyse de la façon d'utiliser JWT dans nodejs ?

很明显,随着payload的信息量增大,token的长度也会增加;

  • 安全性,其实如果token的占用空间过大,Cookie最大存储空间只有4kb前端可以存储在localStorage之类的本地存储,但是会带来一个问题,如果不是放在cookie的话,安全性就会大打折扣,就会有通过js脚本获取到的风险,就意味着任何hacker都可以拿着它做任何事情;

  • 不灵活的时效性,其实JWT的某方面意义在于用户token不需要持久化存储,而是采用服务器校验的方式对token进行有效校验,刚才看到了,签名也是把到期时间一并签名的,如果改变到期时间token就会被篡改,由于没有存储和手动更改时效的方法,所以很难立刻将这个token删掉,如果用户重复登陆两次,生成两个token,那么原则上两个token都是有效的;

总结

以上主要讲了几点:

  • Le principe de JWT est principalement de communiquer avec le token généré par la signature JSON via la clé privée du serveur token进行会话;

  • 也介绍了JWT内部数据的组成,是由Header用来指定签名算法和类型的,payload来传输JSON数据,Signature来对数据进行签名算法,放置篡改;

  • 具体介绍了一下如何通过nodejs使用JWT,通过sign方法进行数据签名,verify方法进行签名验证;

  • 还介绍了一些JWT的不足:

    • 一个是存储空间随着签名数据量的增大而增加;

    • 再有就是安全性,如果由于存储空间过大将无法存储在安全级别相对较高的Cookie中,导致脚本可以随意获取;

    • 再有就是时效性,无法灵活的控制token

    introduit également la composition des données internes de JWT, qui est utilisée ; par l'en-tête pour spécifier Concernant les algorithmes et les types de signature, la charge utile est utilisée pour transmettre les données JSON, et la signature est utilisée pour exécuter des algorithmes de signature sur les données afin d'éviter toute falsification

présente spécifiquement comment utiliser JWT via nodejs et effectuer la signature des données ; via la méthode sign , la méthode verify pour la vérification de la signature

introduit également certaines lacunes de JWT :

    L'un est l'espace de stockage. L'augmentation de la quantité de données de signature augmente ;

    🎜Ensuite, il y a la sécurité. Si l'espace de stockage est trop grand, il ne sera pas stocké dans Cookie avec un niveau de sécurité relativement élevé, ce qui permet au script de l'obtenir à volonté 🎜🎜🎜🎜Ensuite, il y a la rapidité, la rapidité du jeton ne peut pas être contrôlée de manière flexible ; 🎜🎜🎜Voici le 🎜code source de démonstration du nodejs ci-dessus🎜 pour référence 🎜🎜https://github.com/wangzi6224/jwt-usage-nodejs🎜🎜🎜Pour plus de connaissances sur les nœuds, veuillez visiter : 🎜nodejs tutoriel🎜! 🎜

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Étiquettes associées:
    source:juejin.cn
    Déclaration de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
    Tutoriels populaires
    Plus>
    Derniers téléchargements
    Plus>
    effets Web
    Code source du site Web
    Matériel du site Web
    Modèle frontal
    À propos de nous Clause de non-responsabilité Sitemap
    Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!