序章

JSON Web Tokens (JWT)は、承認と情報交換をサポートします。

一般的な使用例の1つは、クライアントがログイン後にセッション情報を保持できるようにすることです。 セッション情報をローカルに保存し、要求時に認証のためにサーバーに渡すことで、サーバーはクライアントが登録ユーザーであることを信頼できます。

警告:JWTをlocalStorageに保存することのセキュリティリスクに注意してください。

この記事では、Node.jsとバニラJavaScriptを使用して、サーバーとクライアントの関係にあるJWTのアプリケーションについて学習します。

前提条件

この記事を続けるには、マシンに次のものをインストールする必要があります。

ステップ1—トークンの生成

jsonwebtokenは、JSONWebトークンの実装です。

ターミナルで次のコマンドを実行することにより、JavaScriptプロジェクトに追加できます。

  1. npm install jsonwebtoken

そして、次のようにファイルにインポートします。

const jwt = require('jsonwebtoken');

トークンに署名するには、次の3つの情報が必要です。

  1. トークンシークレット
  2. トークンでハッシュするデータ
  3. トークンの有効期限

トークンシークレットは、データの暗号化と復号化に使用される長いランダムな文字列です。

このシークレットを生成するための1つのオプションは、次のようにNode.jsの組み込みcryptoライブラリを使用することです。

> require('crypto').randomBytes(64).toString('hex')
// '09f26e402586e2faa8da4c98a35f1b20d6b033c6097befa8be3486a829587fe2f90a832bd3ff9d42710a4da095a2ce285b009f0c3730cd9b8e1af3eb84df6611'

警告:注意してください! secretが単純な場合、トークンの検証プロセスは、許可されていない侵入者によってはるかに簡単に破られます。

次に、このシークレットをプロジェクトの.envファイルに保存します。

.env
TOKEN_SECRET=09f26e402586e2faa8da4c98a35f1b20d6b033c60...

このトークンをNode.jsファイルに入れて使用するには、dotenvを使用する必要があります。

  1. npm install dotenv

そして、次のようにファイルにインポートします。

const dotenv = require('dotenv');

// get config vars
dotenv.config();

// access config var
process.env.TOKEN_SECRET;

トークンでハッシュするデータは、ユーザーIDまたはユーザー名、あるいははるかに複雑なオブジェクトのいずれかです。 いずれの場合も、固有のユーザーの場合は識別子である必要があります。

トークンの有効期限は、1800秒(30分)などの文字列であり、トークンが無効になるまでの時間を詳細に示します。

トークンに署名するための関数の例を次に示します。

function generateAccessToken(username) {
  return jwt.sign(username, process.env.TOKEN_SECRET, { expiresIn: '1800s' });
}

これは、ユーザーのサインインまたはログインの要求から送り返すことができます。

app.post('/api/createNewUser', (req, res) => {
  // ...

  const token = generateAccessToken({ username: req.body.username });
  res.json(token);

  // ...
});

この例では、req request )からusernameの値を取得します。 そして、トークンをres response )として提供します。

これで、jsonwebtokencrypto、およびdotenvを使用してJWTを生成する方法は終わりです。

ステップ2—トークンの認証

Express.jsアプリケーションにJWT認証システムを実装する方法はたくさんあります。

1つのアプローチは、Express.jsのミドルウェア機能を利用することです。

特定のルートにリクエストが送信されると、app.get((req, res) => {})で指定された変数の前に(req, res)変数を中間関数に送信できます。

ミドルウェアは(req, res, next)のパラメータをとる関数です。

  • reqは、送信された要求( GET、POST、DELETE、PUTなど)です。
  • resは、さまざまな方法(res.sendStatus(200)res.json()など)でユーザーに返送できる応答です。
  • nextは、実行をミドルウェアを超えて実際のapp.getサーバー応答に移動するために呼び出すことができる関数です。

認証用のミドルウェア関数の例を次に示します。

const jwt = require('jsonwebtoken');

function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization']
  const token = authHeader && authHeader.split(' ')[1]

  if (token == null) return res.sendStatus(401)

  jwt.verify(token, process.env.TOKEN_SECRET as string, (err: any, user: any) => {
    console.log(err)

    if (err) return res.sendStatus(403)

    req.user = user

    next()
  })
}

このミドルウェア関数を使用したリクエストの例は、次のようになります。

GET https://example.com:4000/api/userOrders
Authorization: Bearer JWT_ACCESS_TOKEN

そして、そのミドルウェアを使用するリクエストの例は、次のようになります。

app.get('/api/userOrders', authenticateToken, (req, res) => {
  // executes after authenticateToken
  // ...
})

このコードは、クライアントから提供されたトークンを認証します。 有効な場合は、リクエストに進むことができます。 有効でない場合は、エラーとして処理できます。

ステップ3—クライアント側トークンの処理

クライアントがトークンを受け取ると、将来のリクエストでユーザー情報を収集するためにトークンを保存したいことがよくあります。

認証トークンを保存するための最も一般的な方法は、HttpOnly cookieです。

クライアント側のJavaScriptコードを使用してCookieを保存するための実装は次のとおりです。

// get token from fetch request
const token = await res.json();

// set token in cookie
document.cookie = `token=${token}`

このアプローチでは、応答をローカルに保存し、サーバーへの将来の要求で参照できるようにします。

これで、トークンの要求、トークンの生成、トークンの受信、新しい要求でのトークンの受け渡し、およびトークンの検証のフローが終了します。

結論

この記事では、JWTと、それらをNode.jsアプリケーションに適用するための1つのアプローチを紹介しました。 このアプローチは、jsonwebtokencryptodotenv、およびexpressの組み合わせに依存していました。

JWTを使用する別のアプローチとして、JSONWebトークンとパスポートを使用してAPI認証を実装する方法があります。

JWTの背景については、「はじめに」のドキュメントがあります。

Node.jsの詳細については、Node.jsトピックページで演習とプログラミングプロジェクトを確認してください。