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 のミドルウェアは通常、req、 res、next の3つのパラメータをもちます。
req、res、next という名前自体は通常、慣例としてこれらを使うことになってます。 ちなみにエラーハンドリングのミドルウェアでは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 トークンを用いた認証の実装方法について説明しました。