Jetstreamでのマルチ認証について
IT技術
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通りでログインができるようになったかと思います。
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ