Help us understand the problem. What is going on with this article?

LaravelでJWTを使って複数ロールのユーザー認証を行う

More than 1 year has passed since last update.

LaravelのAPI開発で、複数ロールのユーザーの認証を行いたい場合があります。一般ユーザーはadminページにはアクセスできない、みたいな感じです。

上記のケースで、JWTを使う場合にどう書くのかをまとめました。1から10まで全部書くと結構な量になるので、要点だけ抜き出して書いていきます。

JWT認証の方法については、以下の記事を参考にさせていただきました。

Laravel + Jwt Auth で認証付きWebAPIを作る

jwt-authのインストール

まず、JWT認証の環境を整えるために、composerでjwt-authをインストールします。

composer require tymon/jwt-auth

上記のコマンドでインストールできますが、Laravelのバージョンによってはerrorが出てインストールに失敗します。(古いjwt-authをインストールしてしまうみたい)。

そこで、composer.jsonに直接バージョンを記述することで対応しました。

"require": {
   ...,
  "tymon/jwt-auth": "^1.0"
},

これでcomposer installを実行すればOK。(一度composer.lockを削除してから)

次に下記のコマンドを実行して、JWT認証の下準備は完了です。

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

// 秘密鍵を生成
php artisan jwt:secret

認証に利用するModelをJWTに対応させる

JWTで認証を行うロールのModelファイルに、以下の記述を追加します。以下はUserモデルの例。

User.php
<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;

// 追加
use Tymon\JWTAuth\Contracts\JWTSubject;

// JWTSubjectインターフェースを継承
class Seller extends Authenticatable implements JWTSubject
{
    use Notifiable;

    // 追加
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    // 追加
    public function getJWTCustomClaims()
    {
        return [];
    }
}

Laravelが最初から用意してくれているUser.phpの場合は、NotifiableやAuthenticatableをuseする記述がありますが、自分で用意した場合には当然書かれていないので、忘れないように注意です。

auth.phpで新しいProviderを追加

認証周りの情報は、config/auth.phpに記述されています。

今回、ポイントとなるのは'provider'の箇所。

auth.php
'providers' => [
  'users' => [
    'driver' => 'eloquent',
      'model' => App\User::class,
  ],
],

providersにusersが定義されていますね。この記述により、Auth::check('user')などと書けば、Laravelが用意してくれているログインロジックでuserモデルのログインチェックを行うことができます。

ただ、デフォルトの記述ではJWT認証に対応していません。また、providerがuserしか記述されていないので、このままでは他のモデルのログインチェックもできません。

そこで、auth.phpをの該当箇所を以下のように変更します。

auth.php
'guards' => [
  ...
  // 追加
  'user' => [
    'driver' => 'jwt',
    'provider' => 'users',
  ],

  // 追加
  'admin' => [
    'driver' => 'jwt',
    'provider' => 'users',
  ]
],

// 省略

'providers' => [
  'users' => [
    'driver' => 'eloquent',
    'model' => App\User::class,
  ],

  // 追加
  'admins' => [
    'driver' => 'eloquent',
    'model' => App\Admin::class,
  ]
]

これで、Auth::chcek('admin')と書けば、Adminモデルの認証をJWTで行ってくれるようになります。もちろん、Auth::check('user')ならUserモデルの認証を行います。

ちなみに、auth.phpの下部には'passwords'というkeyもありますが、こちらはパスワードリセットの際に使います。

JWT認証を試してみる

適当にルーティングを設定して、簡易的なアクションメソッドを書いてみます。こんな感じ。

UserController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    public function login(Request $request)
    {
        $credentials = request->only(['email', 'password']);

        if (!$token = auth('user')->attempt($credentials)) {
          return response()->json([
            'message' => 'Unauthroized',
          ], 400)
        }

       return response()->json([
         'token' => $token,
         'token_type' => 'bearer',
         'expire_in' => auth('user')->factory()->getTTL(),
       ]), 200;
    }
}

emailが'test@example.com'、パスワードが'test'というユーザーがuserテーブルに入っているという前提で、以下のようなcurlコマンドを実行します。

curl -X POST -H "Content-Type: application/json" -d '{"email": "test@example.com", "password": "test"}' localhost:3000/api/users/login

認証に成功すれば、以下のようなパラメータが返ってきます。

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6MzUwMFwvYXBpXC9zaG9wc1wvbG9naW4iLCJpYXQiOjE1NjYxMTg3ODksImV4cCI6MTU2NjEyMjM4OSwibmJmIjoxNTY2MTE4Nzg5LCJqdGkiOiJxQllMQ3FPUXJqR3RGNDkyIiwic3ViIjoxLCJwcnYiOiIzMmRjMGZhMTI2YTljMzc1ZDYyZjEyMmQ4MzhjMmY0OGEyZDBmMDAyIn0.Ygme5PnhnGoIRNm8LfjFEgIFFY641ehRVwesYgyRV3A","token_type":"bearer","expire_in":60}

'token'に続く長い文字列がJWT認証に必要なパラメータです。

あとはaxiosなどでAPIを叩く際、ヘッダーにこの値をセットすればOKということになります。localStorageなんかに保存しておいて、axiosのintercepterの際にセットするのが簡単かなと思います。

まとめ

Laravelが用意してくれている機能と、ライブラリのおかげで簡単にJWT認証を実装できました。ただ、裏でどんな処理が行われているかはブラックボックスなので、そこらへんを掘り下げて見ていく必要がありそうです。

akashixi
29歳未経験からWeb系エンジニアとして働き始めました。拙いながらも積極的にアウトプットしていこうと思います。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした