
Jetstreamでのマルチ認証について
2021.12.21
Jetstreamを使って2種類のユーザー認証をする
今回はJerstreamを使って2種類のユーザーを認証していきます。
具体的には User と Worker の2種類のユーザーを作成して認証します。
Jestreamをインストール
まずはJetstreamをインストールしていきます。
私の場合既に立ち上げたアプリにJetstreamをインストールしたので、
以下のようなコマンドでインストール
1 2 | $ composer require laravel/jetstream $ php artisan jetstream:install livewire |
Jetstreamにはteamsというチーム機能をサポートするものがありますが今回は使用しません。
(マルチ認証の際に少し悪さをしたため)
Jetstreamをインストールした後は以下のコマンドで環境を構築し、DBのマイグレートまで行いましょう。
1 2 | npm install && npm run dev php artisan migrate |
これでJetstreamを使う準備は整いました。
認証機能の実装に進みましょう。
マルチ認証の実装
Jetstreamでは標準でUserの認証機能が実装されています。
Workerの認証機能はこのUserの機能をコピーして一部修正するような形で実現していきます。
まずは WorkerLoginResponse.php を作成していきます。
これは vender/laravel/fortify/src/Http/Responses/LoginResponse.php を参考に作成していきます。
app/Responseディレクトリを作成しその中にWorkerLoginResponse.phpを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace App\Responses; use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract; class WorkerLoginResponse implements LoginResponseContract { /** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Symfony\Component\HttpFoundation\Response */ public function toResponse($request) { return $request->wantsJson() ? response()->json(['two_factor' => false]) : redirect()->intended('worker/dashboard'); // ログイン後に遷移させたいリダイレクト先を指定 } } |
ここでWorker用のログイン画面も作成しておきましょう、と言ってもここでは標準で実装されているlogin.blade.phpを修正する形を取ります。
issetでguard変数の有無を判別してURLを分けています。
次にapp/Actions/Workerディレクトリを作成しAttemptToAuthenticate.phpを作成します。
こちらはvendor/laravel/fortify/src/Actions/AttemptToAuthenticate.phpを参考に作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <?php namespace App\Actions\Worker; use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Validation\ValidationException; use Laravel\Fortify\Fortify; use Laravel\Fortify\LoginRateLimiter; class AttemptToAuthenticate { /** * The guard implementation. * * @var \Illuminate\Contracts\Auth\StatefulGuard */ protected $guard; /** * The login rate limiter instance. * * @var \Laravel\Fortify\LoginRateLimiter */ protected $limiter; /** * Create a new controller instance. * * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @param \Laravel\Fortify\LoginRateLimiter $limiter * @return void */ public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter) { $this->guard = $guard; $this->limiter = $limiter; } /** * Handle the incoming request. * * @param \Illuminate\Http\Request $request * @param callable $next * @return mixed */ public function handle($request, $next) { if (Fortify::$authenticateUsingCallback) { return $this->handleUsingCustomCallback($request, $next); } if ($this->guard->attempt( $request->only(Fortify::username(), 'password'), $request->filled('remember')) ) { return $next($request); } $this->throwFailedAuthenticationException($request); } /** * Attempt to authenticate using a custom callback. * * @param \Illuminate\Http\Request $request * @param callable $next * @return mixed */ protected function handleUsingCustomCallback($request, $next) { $user = call_user_func(Fortify::$authenticateUsingCallback, $request); if (! $user) { return $this->throwFailedAuthenticationException($request); } $this->guard->login($user, $request->filled('remember')); return $next($request); } /** * Throw a failed authentication validation exception. * * @param \Illuminate\Http\Request $request * @return void * * @throws \Illuminate\Validation\ValidationException */ protected function throwFailedAuthenticationException($request) { $this->limiter->increment($request); throw ValidationException::withMessages([ Fortify::username() => [trans('auth.failed')], ]); } } |
ここで作成したAttemptToAuthenticate.phpとのちに作成するLoginControllerで使用するWorkerLoginServiceProvider.phpを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php namespace App\Providers; use App\Http\Controllers\Auth\WorkerLoginController; use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Support\Facades\Auth; use App\Actions\Worker\AttemptToAuthenticate; use Illuminate\Support\ServiceProvider; class WorkerLoginServiceProvider extends ServiceProvider { /** * Register services. * * @return void */ public function register() { $this->app ->when([WorkerLoginController::class, AttemptToAuthenticate::class]) ->needs(StatefulGuard::class) ->give(function () { return Auth::guard('worker'); }); } /** * Bootstrap services. * * @return void */ public function boot() { // } } |
たった今作成したWorkerLoginServiceProvider.phpが反映されるようにapp.phpを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 〜省略〜 /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Providers\FortifyServiceProvider::class, App\Providers\JetstreamServiceProvider::class, App\Providers\WorkerLoginServiceProvider::class, //この行を追加 App\Providers\CompanyLoginServiceProvider::class, 〜省略〜 |
ここでWorker認証用のWorkerLoginControllerを作成していきます。
1 | $ php artisan make:controller Auth/LoginController |
vendor/laravel/fortify/src/Http/Controllers/AuthenticatedSessionController.php を参考に WorkerLoginControllerを作成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Http\Request; use Illuminate\Routing\Pipeline; use App\Actions\Worker\AttemptToAuthenticate; use Laravel\Fortify\Actions\PrepareAuthenticatedSession; use App\Responses\WorkerLoginResponse; use Laravel\Fortify\Contracts\LogoutResponse; use Laravel\Fortify\Http\Requests\LoginRequest; class workerLoginController extends Controller { /** * The guard implementation. * * @var \Illuminate\Contracts\Auth\StatefulGuard */ protected $guard; /** * Create a new controller instance. * * @param \Illuminate\Contracts\Auth\StatefulGuard * @return void */ public function __construct(StatefulGuard $guard) { $this->guard = $guard; } /** * Show the login view. * * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory */ public function create() { return view('auth.login', ['guard' => 'worker']); } |
Workerとしてログインした後のダッシュボード表示用にWorkerDashboardController.phpとWorker/dashboard.blade.phpを作成していきます。
1 | $ php artisan make:controller WorkerDashboardController |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Worker; class WorkerDashboardController extends Controller { public function index() { $workers = Worker::all(); return view('worker.dashboard', ['workers' => $workers,]); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <x-app-layout> <x-slot name="header"> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> <!-- わかりやすいようにここを修正--> Workerダッシュボード </h2> </x-slot> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg"> <x-jet-welcome /> </div> </div> </div> <div class="company-list"> @foreach($workers as $worker) <a href="{{ route('workers.profile', ['id' => $worker->id]) }}"> <p>{{ $worker->name }}</p> </a> <p>{{ $worker->experience_year }} 年</p> <p>{{ $worker->area }}</p> @endforeach </div> </x-app-layout> |
また未ログイン時にダッシュボードにアクセスした時にログイン画面にリダイレクトされるようAuthenticate.phpを編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php namespace App\Http\Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware; class Authenticate extends Middleware { /** * Get the path the user should be redirected to when they are not authenticated. * * @param \Illuminate\Http\Request $request * @return string|null */ protected function redirectTo($request) { if (! $request->expectsJson()) { if($request->is('worker/*')) { return route('worker.login'); } if($request->is('company/*')) { return route('company.login'); } return route('login'); } } } |
Worker用のログイン画面とダッシュボードのルーティングをしていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php use App\Http\Controllers\WorkerDashboardController; use App\Http\Controllers\Auth\WorkerLoginController; use App\Http\Controllers\Auth\WorkerRegisterController; use App\Http\Controllers\UserController; use App\Http\Controllers\WorkerController; use Illuminate\Support\Facades\Route; use App\Models\User; // Route::get('/', 'HomeController@index')->name('home'); Route::get('/', function () { return view('welcome'); }); Route::prefix('worker')->group(function () { Route::get('login', [WorkerLoginController::class, 'create'])->name('worker.login'); Route::post('login', [WorkerLoginController::class, 'store']); Route::get('register', [WorkerRegisterController::class, 'create'])->name('worker.register'); Route::post('register', [WorkerRegisterController::class, 'store']); Route::middleware('auth:worker')->group(function () { Route::get('dashboard', [WorkerDashboardController::class, 'index']); }); }); |
最後に auth.phpにWorler用の認証ガードを定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 〜省略〜 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'worker' => [ 'driver' => 'session', 'provider' => 'workers', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', 'hash' => false, ], 〜省略〜 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'workers' => [ 'driver' => 'eloquent', 'model' => App\Models\Worker::class, ], 〜省略〜 'passwords' => [ 'users' => [ 'provider' => 'users', 'table' => 'password_resets', 'expire' => 60, 'throttle' => 60, ], 'workers' => [ 'provider' => 'workers', 'table' => 'password_resets', 'expire' => 60, 'throttle' => 60, ], |
以上でマルチ認証が完成しました!!
WorkerとUserの2通りでログインができるようになったかと思います。
書いた人はこんな人

IT技術6月 6, 2023encoding.jsを使ってJavaScriptで文字コードを変換する
IT技術1月 19, 2023Laravelでboolean型にしたはずのデータがint型で返ってくる
IT技術10月 17, 2022メンターをやってみて逆に学んだこと
IT技術7月 1, 2022Swaggerで作成したAPIドキュメントをPDF化