Express で JWT を用いた認証を実装する方法

ここでは Node.js 上で Express を利用してウェブアプリケーション (サービス) を実装する際の認証機構として、 JWT を利用する方法について説明します。

JWT (JSON Web Token) については、「JWT」を参考にしてください。

必要なパッケージのインストール

ここでは次の3つのパッケージをインストールします。

$ npm install --save express body-parser jsonwebtoken

Express を用いて http リクエストを受け付けますので、express をインストールします。

body-parser は HTTP の POST リクエストのパラメータを req.body で簡単に受け取れるようにします。

また JWT を使うために jsonwebtoken を使います。

JWT トークンの生成と検証

index.js は次の通りです。3000 番ポートをリスニングし、 /login へのアクセスでトークンを返し、/test へのアクセスでトークンの検証を行ってます。

const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const config = require('./config');
const authenticate = require('./authenticate');
const app = express();

app.use(bodyParser.json());

app.post('/login', (req, res) => {
  const payload = {
    email: req.body.email
  };

  const token = jwt.sign(payload, config.jwt.secret, config.jwt.options);

  const body = {
    email: req.body.email,
    token: token,
  };
  res.status(200).json(body);
});

app.get('/test', authenticate, (req, res) => {
  res.status(200).json({
    message: 'Hello!',
    authEmail: req.jwtPayload.email,
  });
});

app.listen(3000, () => console.log('Listening on port 3000...'));

ここで config.js は次の通り。

module.exports = {
  jwt: {
    secret: 'secret_key_goes_here',
    options: {
      algorithm: 'HS256',
      expiresIn: '10m'
    }
  }
};

トークンを生成するためのオプションとシークレットを記載しています。

特にシークレットについては複数箇所で参照しないといけないですし、署名アルゴリズムも含め、 運用時の変更等があるので外出しに設定をもっています。

トークンの検証箇所は次の通りです。

Express のミドルウェアとして実装します。Express のミドルウェアは通常、reqresnext の3つのパラメータをもちます。

reqresnext という名前自体は通常、慣例としてこれらを使うことになってます。 ちなみにエラーハンドリングのミドルウェアでは4個のパラメータを受け取ります。

const jwt = require('jsonwebtoken');
const config = require('./config');

module.exports = function authenticate(req, res, next) {
  try {
    const token = req.headers.authorization;
    const decoded = jwt.verify(token, config.jwt.secret);
    console.log(decoded);
    req.jwtPayload = decoded;
    next();
  } catch (err) {
    return res.status(401).json({
      message: 'Not authenticated'
    });
  }
};

上で記載した app.get ですが、もし認証が必要なければ、

app.get('/test', (req, res) => {
  res.status(200).json({
    message: 'Hello!',
    authEmail: req.jwtPayload.email,
  });
});

なのですが、この箇所にだけ認証を設定するので、

app.get('/test', authenticate, (req, res) => {
  res.status(200).json({
    message: 'Hello!',
    authEmail: req.jwtPayload.email,
  });
});

となります。

なお、ここでは req (リクエスト) の jwtPayload 属性として、authenticate ミドルウェアでセットした値 (メールアドレス) が取得できることも確認しています。

Postman を使った動作確認

上のコードを実行します。

$ node index.js
Listening on port 3000...

これでポート 3000 番で HTTP リクエストを待ち受け状態になっています。

テスト用のリクエストを送信してみましょう。

HTTP ヘッダを任意の値にセットして JSON の生リクエストを送ったりするには、Postman を使うと便利です。

リクエストの送信は次のようにします。

HTTP POST リクエストで http://localhost:3000/login 向けにします。 Body 部には JSON の生データ (Raw data) として、email の値を設定します。

これで Send ボタンを押すと、画面の下部にレスポンスが表示されます。

この token (トークン) が JWT トークンです。

このトークンは jwt.io の JWT デバッガなどで、中身を確認できます。

さて、次に Postman で HTTP ヘッダの Authorization ヘッダに上のトークンをセットして、 http://localhost:3000/test 宛てにリクエストを送信してみます。

Hello というメッセージが返れば認証が成功したことがわかります。

トークンを不正に書き換えたり、あるいは有効期限を過ぎたりした時に、次のように認証エラーが表示されることも確認できると思います。

上のコードではトークンの有効期限は config.js にて 10分 (10m) に設定しています。

以上、ここでは JWT トークンを用いた認証の実装方法について説明しました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Node.js 入門