• トップ
  • ブログ一覧
  • Jetstreamでのマルチ認証について
  • Jetstreamでのマルチ認証について

    Jetstreamでのマルチ認証

    Jetstreamを使って2種類のユーザー認証をする

    今回はJerstreamを使って2種類のユーザーを認証していきます。

    具体的には User と Worker の2種類のユーザーを作成して認証します。

    Jestreamをインストール

    まずはJetstreamをインストールしていきます。

    私の場合既に立ち上げたアプリにJetstreamをインストールしたので、

    以下のようなコマンドでインストール

    1$ composer require laravel/jetstream
    2$ php artisan jetstream:install livewire

    Jetstreamにはteamsというチーム機能をサポートするものがありますが今回は使用しません。

    (マルチ認証の際に少し悪さをしたため)

    Jetstreamをインストールした後は以下のコマンドで環境を構築し、DBのマイグレートまで行いましょう。

    1npm install && npm run dev
    2php artisan migrate

    これでJetstreamを使う準備は整いました。

    認証機能の実装に進みましょう。

    マルチ認証の実装

    Jetstreamでは標準でUserの認証機能が実装されています。

    Workerの認証機能はこのUserの機能をコピーして一部修正するような形で実現していきます。

    まずは WorkerLoginResponse.php を作成していきます。

    これは vender/laravel/fortify/src/Http/Responses/LoginResponse.php を参考に作成していきます。

    app/Responseディレクトリを作成しその中にWorkerLoginResponse.phpを作成します。

    1<?php
    2
    3namespace App\Responses;
    4
    5use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
    6
    7class WorkerLoginResponse implements LoginResponseContract
    8{
    9    /*
    10     * Create an HTTP response that represents the object.
    11     *
    12     * @param  \Illuminate\Http\Request  $request
    13     * @return \Symfony\Component\HttpFoundation\Response
    14     */
    15    public function toResponse($request)
    16    {
    17        return $request->wantsJson()
    18            ? response()->json(['two_factor' => false])
    19            : redirect()->intended('worker/dashboard'); // ログイン後に遷移させたいリダイレクト先を指定
    20    }
    21}

    ここでWorker用のログイン画面も作成しておきましょう、と言ってもここでは標準で実装されているlogin.blade.phpを修正する形を取ります。

    issetでguard変数の有無を判別してURLを分けています。

    次にapp/Actions/Workerディレクトリを作成しAttemptToAuthenticate.phpを作成します。

    こちらはvendor/laravel/fortify/src/Actions/AttemptToAuthenticate.phpを参考に作成します。

    1<?php
    2
    3namespace App\Actions\Worker;
    4
    5use Illuminate\Contracts\Auth\StatefulGuard;
    6use Illuminate\Validation\ValidationException;
    7use Laravel\Fortify\Fortify;
    8use Laravel\Fortify\LoginRateLimiter;
    9
    10class AttemptToAuthenticate
    11{
    12    /*
    13     * The guard implementation.
    14     *
    15     * @var \Illuminate\Contracts\Auth\StatefulGuard
    16     */
    17    protected $guard;
    18
    19    /**
    20     * The login rate limiter instance.
    21     *
    22     * @var \Laravel\Fortify\LoginRateLimiter
    23     */
    24    protected $limiter;
    25
    26    /**
    27     * Create a new controller instance.
    28     *
    29     * @param  \Illuminate\Contracts\Auth\StatefulGuard  $guard
    30     * @param  \Laravel\Fortify\LoginRateLimiter  $limiter
    31     * @return void
    32     */
    33    public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter)
    34    {
    35        $this->guard = $guard;
    36        $this->limiter = $limiter;
    37    }
    38
    39    /**
    40     * Handle the incoming request.
    41     *
    42     * @param  \Illuminate\Http\Request  $request
    43     * @param  callable  $next
    44     * @return mixed
    45     */
    46    public function handle($request, $next)
    47    {
    48        if (Fortify::$authenticateUsingCallback) {
    49            return $this->handleUsingCustomCallback($request, $next);
    50        }
    51
    52        if ($this->guard->attempt(
    53            $request->only(Fortify::username(), 'password'),
    54            $request->filled('remember'))
    55        ) {
    56            return $next($request);
    57        }
    58
    59        $this->throwFailedAuthenticationException($request);
    60    }
    61
    62    /**
    63     * Attempt to authenticate using a custom callback.
    64     *
    65     * @param  \Illuminate\Http\Request  $request
    66     * @param  callable  $next
    67     * @return mixed
    68     */
    69    protected function handleUsingCustomCallback($request, $next)
    70    {
    71        $user = call_user_func(Fortify::$authenticateUsingCallback, $request);
    72
    73        if (! $user) {
    74            return $this->throwFailedAuthenticationException($request);
    75        }
    76
    77        $this->guard->login($user, $request->filled('remember'));
    78
    79        return $next($request);
    80    }
    81
    82    /**
    83     * Throw a failed authentication validation exception.
    84     *
    85     * @param  \Illuminate\Http\Request  $request
    86     * @return void
    87     *
    88     * @throws \Illuminate\Validation\ValidationException
    89     */
    90    protected function throwFailedAuthenticationException($request)
    91    {
    92        $this->limiter->increment($request);
    93
    94        throw ValidationException::withMessages([
    95            Fortify::username() => [trans('auth.failed')],
    96        ]);
    97    }
    98}

    ここで作成したAttemptToAuthenticate.phpとのちに作成するLoginControllerで使用するWorkerLoginServiceProvider.phpを作成します。

    1<?php
    2
    3namespace App\Providers;
    4
    5use App\Http\Controllers\Auth\WorkerLoginController;
    6use Illuminate\Contracts\Auth\StatefulGuard;
    7use Illuminate\Support\Facades\Auth;
    8use App\Actions\Worker\AttemptToAuthenticate;
    9use Illuminate\Support\ServiceProvider;
    10
    11class WorkerLoginServiceProvider extends ServiceProvider
    12{
    13    /*
    14     * Register services.
    15     *
    16     * @return void
    17     */
    18    public function register()
    19    {
    20        $this->app
    21            ->when([WorkerLoginController::class, AttemptToAuthenticate::class])
    22            ->needs(StatefulGuard::class)
    23            ->give(function () {
    24                return Auth::guard('worker');
    25            });
    26    }
    27
    28    /**
    29     * Bootstrap services.
    30     *
    31     * @return void
    32     */
    33    public function boot()
    34    {
    35        //
    36    }
    37}

    たった今作成したWorkerLoginServiceProvider.phpが反映されるようにapp.phpを修正します。

    1        〜省略〜
    2         /*
    3         * Application Service Providers...
    4         */
    5        App\Providers\AppServiceProvider::class,
    6        App\Providers\AuthServiceProvider::class,
    7        // App\Providers\BroadcastServiceProvider::class,
    8        App\Providers\EventServiceProvider::class,
    9        App\Providers\RouteServiceProvider::class,
    10        App\Providers\FortifyServiceProvider::class,
    11        App\Providers\JetstreamServiceProvider::class,
    12        App\Providers\WorkerLoginServiceProvider::class, //この行を追加
    13        App\Providers\CompanyLoginServiceProvider::class,
    14
    15       〜省略〜

    ここでWorker認証用のWorkerLoginControllerを作成していきます。

    1$ php artisan make:controller Auth/LoginController

    vendor/laravel/fortify/src/Http/Controllers/AuthenticatedSessionController.php を参考に WorkerLoginControllerを作成。

    1<?php
    2
    3namespace App\Http\Controllers\Auth;
    4
    5use App\Http\Controllers\Controller;
    6use Illuminate\Contracts\Auth\StatefulGuard;
    7use Illuminate\Http\Request;
    8use Illuminate\Routing\Pipeline;
    9use App\Actions\Worker\AttemptToAuthenticate;
    10use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
    11use App\Responses\WorkerLoginResponse;
    12use Laravel\Fortify\Contracts\LogoutResponse;
    13use Laravel\Fortify\Http\Requests\LoginRequest;
    14
    15class workerLoginController extends Controller
    16{
    17    /*
    18     * The guard implementation.
    19     *
    20     * @var \Illuminate\Contracts\Auth\StatefulGuard
    21     */
    22    protected $guard;
    23
    24    /**
    25     * Create a new controller instance.
    26     *
    27     * @param  \Illuminate\Contracts\Auth\StatefulGuard
    28     * @return void
    29     */
    30    public function __construct(StatefulGuard $guard)
    31    {
    32        $this->guard = $guard;
    33    }
    34
    35    /**
    36     * Show the login view.
    37     *
    38     * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
    39     */
    40    public function create()
    41    {
    42        return view('auth.login', ['guard' => 'worker']);
    43    }

    Workerとしてログインした後のダッシュボード表示用にWorkerDashboardController.phpとWorker/dashboard.blade.phpを作成していきます。

    1$ php artisan make:controller WorkerDashboardController
    1<?php
    2
    3namespace App\Http\Controllers;
    4
    5use Illuminate\Http\Request;
    6use App\Models\Worker;
    7
    8class WorkerDashboardController extends Controller
    9{
    10    public function index()
    11    {
    12        $workers = Worker::all();
    13
    14        return view('worker.dashboard', ['workers' => $workers,]);
    15    }
    16}
    1<x-app-layout>
    2    <x-slot name="header">
    3        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
    4            <!-- わかりやすいようにここを修正-->
    5            Workerダッシュボード
    6        </h2>
    7    </x-slot>
    8
    9    <div class="py-12">
    10        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
    11            <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
    12                <x-jet-welcome />
    13            </div>
    14        </div>
    15    </div>
    16
    17    <div class="company-list">
    18        @foreach($workers as $worker)
    19        <a href="{{ route('workers.profile', ['id' => $worker->id]) }}">
    20                <p>{{ $worker->name }}</p>
    21            </a>
    22            <p>{{ $worker->experience_year }}</p>
    23            <p>{{ $worker->area }}</p>
    24        @endforeach
    25    </div>
    26</x-app-layout>

    また未ログイン時にダッシュボードにアクセスした時にログイン画面にリダイレクトされるようAuthenticate.phpを編集します。

    1<?php
    2
    3namespace App\Http\Middleware;
    4
    5use Illuminate\Auth\Middleware\Authenticate as Middleware;
    6
    7
    8class Authenticate extends Middleware
    9{
    10    /*
    11     * Get the path the user should be redirected to when they are not authenticated.
    12     *
    13     * @param  \Illuminate\Http\Request  $request
    14     * @return string|null
    15     */
    16    protected function redirectTo($request)
    17    {
    18        if (! $request->expectsJson()) {
    19
    20            if($request->is('worker/*')) {
    21                return route('worker.login');
    22            }
    23            
    24            if($request->is('company/*')) {
    25                return route('company.login');
    26            }
    27
    28            return route('login');
    29        }
    30    }
    31}

    Worker用のログイン画面とダッシュボードのルーティングをしていきます。

    1<?php
    2
    3use App\Http\Controllers\WorkerDashboardController;
    4use App\Http\Controllers\Auth\WorkerLoginController;
    5use App\Http\Controllers\Auth\WorkerRegisterController;
    6use App\Http\Controllers\UserController;
    7use App\Http\Controllers\WorkerController;
    8use Illuminate\Support\Facades\Route;
    9use App\Models\User;
    10
    11// Route::get('/', 'HomeController@index')->name('home');
    12Route::get('/', function () {
    13    return view('welcome');
    14});
    15
    16Route::prefix('worker')->group(function () {
    17    Route::get('login', [WorkerLoginController::class, 'create'])->name('worker.login');
    18    Route::post('login', [WorkerLoginController::class, 'store']);
    19
    20    Route::get('register', [WorkerRegisterController::class, 'create'])->name('worker.register');
    21    Route::post('register', [WorkerRegisterController::class, 'store']);
    22
    23    Route::middleware('auth:worker')->group(function () {
    24        Route::get('dashboard', [WorkerDashboardController::class, 'index']);
    25    });
    26});

    最後に auth.phpにWorler用の認証ガードを定義します。

    1〜省略〜
    2'guards' => [
    3        'web' => [
    4            'driver' => 'session',
    5            'provider' => 'users',
    6        ],
    7
    8        'worker' => [
    9            'driver' => 'session',
    10            'provider' => 'workers',
    11        ],
    12
    13       'api' => [
    14            'driver' => 'token',
    15            'provider' => 'users',
    16            'hash' => false,
    17        ],
    18〜省略〜
    19'providers' => [
    20        'users' => [
    21            'driver' => 'eloquent',
    22            'model' => App\Models\User::class,
    23        ],
    24
    25        'workers' => [
    26            'driver' => 'eloquent',
    27            'model' => App\Models\Worker::class,
    28        ],
    29〜省略〜
    30'passwords' => [
    31        'users' => [
    32            'provider' => 'users',
    33            'table' => 'password_resets',
    34            'expire' => 60,
    35            'throttle' => 60,
    36        ],
    37
    38        'workers' => [
    39            'provider' => 'workers',
    40            'table' => 'password_resets',
    41            'expire' => 60,
    42            'throttle' => 60,
    43        ],

    以上でマルチ認証が完成しました!!

    WorkerとUserの2通りでログインができるようになったかと思います。

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background