テックブログ

  1. Express
  2. 370 view

Express【Node.js】のAPIにJWT認証を導入しよう!

はじめに

本記事では、本格的なAPI開発では避けては通れない認証をNode.jsで実装する方法を解説します。チュートリアル形式になっているので最初から手順通り進めていけば、実際のアプリケーションに認証を導入する方法が理解できるようになっています!

サンプルコードはこちらからどうぞ!

準備

以下のツールを使います。インストールしてない方はリンク元からインストールしてください!

Node.js

Postman

作るもの

認証付きAPIサーバを構築します。以下の2つのルートを作成します。

[POST] /api/login
ユーザ名とパスワードをリクエストするとトークンが返ってくるエンドポイント。

[GET] /api/me
トークンを付与してリクエストすると認証したユーザのデータが返ってくるエンドポイント。

プロジェクト作成

プロジェクトフォルダを作成します。ここではプロジェクト名をexpress-api-jwtとします。

mkdir express-api-jwt
cd express-api-jwt

プロジェクトフォルダをnpmで初期化します。

npm init

色々聞かれますが、全てEnterを押して次に進みます。初期化が終わるとプロジェクトフォルダにpackage.jsonが作成されます。

次にExpressなど必要なパッケージをインストールします。

npm install express body-parser morgan mongoose jsonwebtoken --save

簡単にパッケージの説明をしておきます。詳しくはググってください。

  • expressはNode.js上で動く人気のフレームワークです。ドキュメントはこちら
  • mongooseは、MongoDBデータベースとやり取りするためのパッケージです。
  • morganはリクエストをコンソール上に表示して可視化してくれるパッケージです。
  • body-parserはリクエストからパラメータを取り出してくれるパッケージです。
  • jsonwebtokenはJSON Web Tokenを発行したり認証してくれるパッケージです。

プロジェクトフォルダにindex.jsというファイルを作成して以下のように記述してみましょう。

// パッケージの読み込み
var express = require('express');

var app = express();

var morgan = require('morgan');

var port = process.env.PORT || 8080;

app.use(morgan('dev'));

var apiRoutes = express.Router();

// ルートに/apiプレフィックスをつける
app.use('/api', apiRoutes);

// ルート
apiRoutes.get('/healthcheck', function(req, res){
  res.send('hello world!');
});

app.listen(port);
console.log('サーバを起動しました。http://localhost:' + port);

ひとまずこの状態で立ち上げてみます。以下のコマンドを実行してみてください。

node index.js

※エラーが出る場合は以下のようにしてください。

sudo node index.js

画像のように表示されれば成功です。

ブラウザを開いて
http://localhost:8080/api/healthcheck
にアクセスしてみましょう。

またコンソールにもリクエストのログが表示されます。

以上でセットアップは完了です。

以降では認証方法の導入に入りますが、一つ注意点があります。Node.js上ではソースコードを変更した場合でも一度再起動しないと変更が反映されません。command + C(Windowsの場合はControl + C)でサーバを停止した後、再びnode index.jsをする必要があります。いちいちめんどくさいよ!って方は以下にNodemonを使った自動リロードの設定方法をまとめておいたので参考にしてください。

Nodemonを使ってNode.jsのソース変更毎に自動リロードする方法

Userモデルの作成

Userを作ったり取得するためにMongooseのモデルを定義します。
app/modelsディレクトリにuser.jsのファイルを作成してください。

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

module.exports = mongoose.model('User', new Schema({
  name: String,
  password: String,
}));

#設定ファイル作成

app/ディレクトリにconfig.jsという設定ファイルを作成して以下のようにしてください。

module.exports = {
  'secret' : 'application-secret-key',
  'database' : 'mongodb://localhost:27017/express-api-jwt',
}

MongoDBのインストール

MongoDBがまだ入っていない方は入れてください。

Macの場合

brew install mongodb

# mongoDBを自動起動
ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist

Windowsの場合

MongoDB 3.0.6(Windows版)をインストールして起動するまでの手順

# ユーザデータ登録

プロジェクト作成の時に作ったindex.jsを以下のように書き換えます。

// パッケージ読み込み
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var mongoose = require('mongoose');

var jwt = require('jsonwebtoken');
var config = require('./config');
var User = require('./app/models/user');

var port = process.env.PORT || 8080;

// MongoDBに接続する
mongoose.connect(config.database, { useNewUrlParser : true});
app.set('secretKey', config.secret);
// body parserの設定
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());

// morganを使ってリクエストをコンソール上に出力できるようにする
app.use(morgan('dev'));

var apiRoutes = express.Router();

// ルートに/apiプレフィックスをつける
app.use('/api', apiRoutes);

// ルート
apiRoutes.get('/healthcheck', function(req, res){
  res.send('hello world!');
});

apiRoutes.get('/signup', function(req, res) {
   var user = new User({
     name: 'サンプルユーザー',
     password: 'password',
   });

   user.save(function(error){
     if(error) {
       throw error;
     }

     console.log('ユーザを作成しました。');
     res.json({ success: true});
   })
});

app.listen(port);
console.log('サーバを起動しました。http://localhost:' + port);

この状態でブラウザで
http://localhost:8080/api/signup
にアクセスしてみてください。

このように表示されれば成功です。

# 認証用ルートを作成する

[POST] /api/loginエンドポイントを作成します。index.jsに以下の記述を追加しましょう。

apiRoutes.post('/login', function(req, res) {

  // リクエストパラメータから名前を取り出して検索する
  User.findOne({
    name: req.body.name
  }, function(error, user) {

    if (error) throw error;
    if (user) {
      // パスワードが正しいか確認します。
      if (user.password != req.body.password) {
        res.json({ success: false, message: 'パスワードが違います。' });
      } else {

        // ユーザとパスワードの組が正しければトークンを発行します。
        // パスワードはpayloadの中に含めないように注意してください。
        const payload = {
          name : user.name
        }
        var token = jwt.sign(payload, app.get('secretKey'));

        // トークンを返します。
        res.json({
          success: true,
          token: token
        });
      }
    } else {
      res.json({ success: false, message: 'ユーザがいません。' });
    }

  });
});

書き上げたらPostmanで[POST] /api/loginにリクエストしてみます。

# 認証ミドルウェアの作成

app/middlewaresディレクトリにverifyToken.jsというファイルを作成しましょう。

var jwt = require('jsonwebtoken');
var config = require('../../config');
function verifyToken(req, res, next) {
  // header か url parameters か post parametersからトークンを取得する
  var token = req.body.token || req.query.token || req.headers['x-access-token'];

  if (token) {

    // jwtの認証をする
    jwt.verify(token, config.secret, function(error, decoded) {
      if (error) {
        return res.json({ success: false, message: 'トークンの認証に失敗しました。' });
      } else {
        // 認証に成功したらdecodeされた情報をrequestに保存する
        req.decoded = decoded;
        next();
      }
    });

  } else {
    // トークンがなければエラーを返す
    return res.status(403).send({
        success: false,
        message: 'トークンがありません。',
    });

  }
}
module.exports = verifyToken;

認証付きルートを作成する

[GET] /api/meエンドポイントを作成します。index.jsに以下の記述を追加しましょう。

var VerifyToken = require('./app/middlewares/VerifyToken');

apiRoutes.get('/me', VerifyToken, function(req, res, next) {
  User.findOne({name: req.decoded.name}, {password: 0},
  function (error, user) {

    if (error) return res.status(500).send("ユーザの取得に失敗しました。");
    if (!user) return res.status(404).send("ユーザが見つかりません。");

    res.status(200).send(user);
  });
});

Postmanを開いて[GET] /api/meにアクセスしてみましょう。

headersのところにkey = x-access-token value=XXXXXXXXXXXXXX(/api/loginで得たtoken)
を設定しましょう。

画像のようにレスポンスが返って来れば成功です!

最後に

お疲れ様です。以上でこのチュートリアルは終わりです。

質問ありましたらお気軽にコメント欄へどうぞ。最後までお付き合いいただきありがとうございました!!

The following two tabs change content below.

riri

半年おきくらいにバックエンドとフロントエンドを行ったり来たり。 25歳。 将棋好き。

Expressの最近記事

  1. Express【Node.js】のAPIにJWT認証を導入しよう!

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。