【Laravel】JWT認証を行う(Laravel9.x + tymon/jwt-auth)

JWT
現在参画しているプロジェクトはフレームワーク「Laravel」上に実装しているのですが、既存プロジェクトの連携ほかいくつかの要件を満たすために認証にJWTを使うことになりました。なんとか設定、実装が出来て運用に目途が経ちそうなので導入について簡単にメモしておきます






Laravelで利用するまでの簡単な手順

手順をざっくり書くとこんな感じ(Laravelは既にインストール済みとする)

  1. laravel/uiのインストール
  2. composerで「tymon/jwt-auth」をインストールする
  3. JWTの初期設定
  4. config/auth.php 設定
  5. User Modelのカスタマイズ
  6. Auth/LoginController.php にログイン処理を追加


参考記事/ドキュメント



1. laravel/uiのインストール

Laravel 8.xからデフォルトのCSSフレームワークが「Tailwind」に変わっていますが、プロジェクトの要件として「Bootstrap5」を使いたいということだったのでlaravel/uiをインストールしました。

$ composer install laravel/ui
$ php artisan ui bootstrap --auth

どうせlaravel/uiでをインストールするならということで、認証処理のコントローラなどはlaravel/uiで用意してくれるものを使用することにしました。以下はそれを前提としています。

補記:属人性を下げる
参考記事にあるように自分でコントローラを用意することも出来るのですが、今回は出来る限りデフォルトのものを使用するようにしています。その方が属人性が下がってメンテナンス性が上がるという判断からです。多くの人が参加するプロジェクトで、かつ全員がコードを正確に読み解けるエンジニアばかりではないという環境だと、独自に書くコードは減らせれば減らせるほど良いです。デフォルトのものならなんらかのドキュメントがあるはずなので。



2. composerで「tymon/jwt-auth」をインストールする

候補のライブラリはいくつかありますが、今回は「tymon/jwt-auth」を使っています。


$ composer require tymon/jwt-auth



3. JWTの初期設定

config/jwt.phpの生成

$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider

.envにJWT_SECRETを生成

$ php artisan jwt:secret



4. config/auth.php 設定

変更点だけ抜粋。

'defaults' => [
   'guard' => 'api',
   'passwords' => 'users',
],

'guards' => [
   'api' => [
       'driver' => 'jwt',
       'provider' => 'users',
   ],
],



5. User Modelのカスタマイズ

次の3つ。

  1. 「use Tymon\JWTAuth\Contracts\JWTSubject;」追記
  2. 「implements JWTSubject」追記
  3. メソッド「getJWTIdentifier()」「getJWTCustomClaims()」追記

サンプル

namespace App\Models;

use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
   use Notifiable;  
  
   /**
    * Get the identifier that will be stored in the subject claim of the JWT.
    *
    * @return mixed
    */
   public function getJWTIdentifier()
   {
       return $this->getKey();
   }

   /**
    * Return a key value array, containing any custom claims to be added to the JWT.
    *
    * @return array
    */
   public function getJWTCustomClaims()
   {
       return [];
   }
}



6. Auth/LoginController.php にログイン処理を追加

Quick start – jwt-auth でAuthController.php として実装しているメソッドを、「app\Http\Controllers\Auth\LoginController.php」に実装します。


以上で準備終わり。


laravel/uiで用意されるログインページ(デフォルトでは/login)にアクセスしてログインすると、ログインが成功しJWTが発行されることが確認出来ます。



このあとやることは

JWTトークンを発行するだけではサービスとして認証出来たとは言えません。ページ毎に認証するわけにはいかないし。というわけでJWTトークンをなんらかの方法で保存し受け渡していく必要があります。

ドキュメントに書かれている候補はこんな感じ。

  • Authorization header
  • Query string parameter
  • Post parameter
  • Cookies
  • Laravel route parameter

SPAならヘッダだけでいけるかも知れませんが、バックエンドと連携するとなるとちょっと厳しい(フロントエンドエンジニアやコーダーのスキルの問題でVueでの実装が微妙なラインなので、基本は昔ながらのフォームでの認証になるはず)。

参考にした記事ではlocalStorageを使っているものが多かったですが、localStorageはセキュリティ上不安があるし、フロントエンドの実装が煩雑になりがちだったのでやめてCookieを使うことにしました。Cookieを良い感じに使うとフロントエンドでは特別なにも実装しなくて良く、またバックエンドの処理も取り回しを全部laravel/uiでインストールされるAuthに任せることが出来るので非常に楽です。


長くなったのでCookieのあたりはまた次の記事で。