ホームページ  >  記事  >  ウェブフロントエンド  >  Nodejs で JWT を使用する方法を簡単に分析します。

Nodejs で JWT を使用する方法を簡単に分析します。

青灯夜游
青灯夜游転載
2023-01-04 21:00:182433ブラウズ

この記事では、JWT について理解し、ノードでの JWT の適用方法と、JWT の長所と短所を紹介します。

Nodejs で JWT を使用する方法を簡単に分析します。

JWT とは

JWT は JSON Web Token の略称です。従来の認証メカニズムでは、ネットワーク アプリケーション環境で認証ソリューションを提供するには、次の手順を実行するだけです。

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

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

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

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

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

このモデルの利点の 1 つは、サーバーが次の時点でユーザーのアクセス許可を終了できることです。データベースにアクセスして、現在のユーザーのセッション情報を変更または削除できます。ただし、欠点もあります。つまり、サーバー クラスターの場合、各サーバーが同じセッション ストレージ情報を取得できるようにするために、すべてのマシンがセッション情報を共有する必要があります。これらの問題は解決できますが、作業量は膨大です。

JWT ソリューションの利点は、この情報が保存されないことです。トークン データはクライアントに保存されます。リクエストが受け入れられるたびに、検証だけが必要になります。 [関連チュートリアルの推奨事項: nodejs ビデオ チュートリアル プログラミング教育 ]

JWT の原則

について簡単に説明します。 JWT 実際の原理は、クライアントが認証リクエストを送信すると、サーバーはユーザーを認証した後に JSON オブジェクトを生成します。これには、おそらく「あなたは誰ですか、何をしているのか、など、有効期限」が含まれます。 " 重要なことは、情報には有効期限が必要であるということです。一般的な形式は次のとおりです:

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

しかし、情報はそのような表面的な方法で渡されることはありません。確立された署名アルゴリズムと一部の機能を通過します。送信したペイロードに関する情報。署名と送信には可逆署名アルゴリズムを使用します。一般的な形式を表すために画像を使用します:

Nodejs で JWT を使用する方法を簡単に分析します。

画像からわかるように、返される情報は大きく3つの部分に分かれており、左側はクライアントに返される署名後の結果、右側は同じくDecodedのソースコードであり、3つの部分は「ドット」で区切られ対応しています。

  • 最初の赤い部分はヘッダーで、主にメソッドを指定します。画像の署名アルゴリズム (デフォルト HS256#) ##) は SHA-256 を使用した HMAC です これは対称アルゴリズムであり、2 つの当事者間で共有されるキーは 1 つだけであり、typ フィールドは JWT タイプとしてマークされます;

  • 2 番目の紫色ペイロードの一部は、実際の JSON オブジェクトです。送信されたデータには 7 つの公式フィールドが使用できます。

      iss (発行者): 発行者
    • exp (有効期限): 有効期限time
    • sub ( subject): Subject
    • aud (audence): Audience
    • nbf (Not Before): 有効時間
    • iat (発行時刻) : 発行時刻
    • jti (JWT ID): 番号
これらのフィールドに加えて、いくつかのカスタムフィールドも作成できます。JWTは暗号化されていないため、デフォルトでは、使用するときはそれを使用するようにしてください。機密データを使用しないように注意してください。

  • 3 番目の部分は

    Signature 署名です。この部分は自分で指定した秘密鍵であり、サーバー上にのみ存在します。ヘッダーで指定されたアルゴリズムを使用します。次の署名メソッドを渡します。

JWT の簡単な使用法

具体的な使用法を体験してみましょう:

ステップ 1: A ## をビルドする必要があります#node

プロジェクト; npm init -y を通じてプロジェクトを初期化します; その後、それぞれ expressjsonwebtokennodemon の依存関係をインストールする必要があります 3 つの依存関係: <pre class="brush:js;toolbar:false;">$ npm i express jsonwebtoken nodemon</pre> 次に、

package.json

scripts フィールドに nodemon app.js# を追加します。 ##コマンド:

"scripts": {
    "start": "nodemon app.js"
},
ステップ 2: ノード アプリケーションを初期化し、ルート ディレクトリに app.js ファイルを作成します。
// app.js

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

app.use(express.json());

app.listen(3000, () => {
  console.log(3000 + " listening..."); // 监听3000端口
});

ステップ 3:

jsonwebtoken

依存関係を導入し、その秘密キーを作成します。インターフェイスとサーバー;

// app.js

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

const jwtKey = "~!@#$%^&*()+,";
// ...
ここの 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,
        });
      }
    );
  }
});
上記のコードでは、database

変数を作成して、次の目的に使用します。ログインを検証するためにローカル アカウントとパスワード データベースの作成をシミュレートします。その後、

/loginpost インターフェイスが確立され、アカウントとパスワードが完全に一致することを確認します。その後、サイン スルーします。 jsonwebtoken パッケージによってインポートされた jwt オブジェクトの下の sign メソッド。このメソッドには 3 つのインターフェイス シグネチャがあります:

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;

这里用到了函数重载的方式实现接口,我们这里将实现最后一个接口签名,第一个参数可以是一个自定义的对象类型,也可以是一个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;
}

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

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

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

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

{
  "username": "username",
  "password": "password"
}

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

Nodejs で JWT を使用する方法を簡単に分析します。

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

Nodejs で JWT を使用する方法を簡単に分析します。

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 });
  });
});

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

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

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

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

###
GET http://localhost:3000/afterlogin
authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNjUyNzg5NzA3LCJleHAiOjE2NTI3ODk3Mzd9.s9fk3YLhxTUcpUgCfIK4xQN58Hk_XEP5y9GM9A8jBbY

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

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

Nodejs で JWT を使用する方法を簡単に分析します。

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

JWT的不足

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

Nodejs で JWT を使用する方法を簡単に分析します。

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

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

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

总结

以上主要讲了几点:

  • JWT の原理は主に、サーバーの秘密キーを介して JSON 署名によって生成された token を使用して会話を行うことです。 JWT の内部データの構成は、署名アルゴリズムとタイプを指定するためのヘッダー、JSON データを送信するためのペイロード、およびデータに対して署名アルゴリズムを実行して改ざんを防止するための署名によって使用されます。

    #詳細な紹介nodejs を介して JWT を使用する方法、
  • sign
  • メソッドを使用してデータ署名を実行する方法、および署名検証のための

    verify

    メソッドを使用する方法を見てみましょう。
  • # には、JWT の欠点もいくつか紹介されています:

    1 つは、署名データの量の増加に伴ってストレージ容量が増加することです。

  • もう 1 つはセキュリティです。保存領域が大きすぎると、比較的セキュリティ レベルの高い

    Cookie

    に保存されず、スクリプトが勝手に取得されてしまいます。
    • 次に、柔軟に制御できない適時性があります。

      token
    • の適時性;
    • これは、参考のため、上記の nodejs の

      デモ ソース コード です;

      https://github.com/wangzi6224/jwt-usage-nodejs
  • ノード関連の知識については、
nodejs チュートリアル
を参照してください。

以上がNodejs で JWT を使用する方法を簡単に分析します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。