見出し画像

Laravel学習記録 #026 認証について学ぶ

Laravelの認証機能について学習したものをまとめてます。

認証機能について

  • Laravelの認証機能は「ガード」と「プロバイダ」で構成される

  • ガードは、ユーザーがアプリケーションにアクセスするたびに、そのユーザーが認証されたユーザーであることを確認する方法

  • プロバイダは、データベースなどの永続ストレージからユーザーを取得する方法

  • config/auth.phpで設定可能

  • スターターキットとしてLaravel Breeze、Laravel Jetstreamなどがある

  • データベースはLaravel標準のUserモデルを使うと簡単に実装可能

  • 独自で認証機能の作成も可能

スターターキットで認証機能を作成

マニュアル通りにひとまずスターターキットで認証の流れを抑えてみます。
ググると作り方を説明してくれている記事が多くヒットするので、一番簡単にできます。
とはいえ、実務ではこのまま使うことはないんだろうなとも思います。
その辺は後日まとめようかな。

スターターキットのインストール

Laravel Breezeをインストールします。
Laravelの認証機能の最小限の機能が入ってます。

composer require laravel/breeze --dev

インストール後以下のコマンドを実行

php artisan breeze:install
php artisan migrate
npm install
npm run dev


認証してみる

http://127.0.0.1/register
にアクセスするとユーザーの登録画面が表示されます。
これはLaravel Breezeが用意してくれているやつでほんとあっという間ですね。
ではまず、認証ようのユーザーを登録します。


実行するとユーザーの登録が完了します。
http://127.0.0.1/login
でログインしてみましょう。

デフォルトではemailとパスワードで認証を行います。
ログイン後ダッシュボードが表示されていれば認証完了です。

こんな感じで簡単に認証機能が実装できます。

とはいえ、簡単すぎて仕組みがわからない。。。

認証機能の内部をほんの少しのぞいてみる

少しだけ、導入した機能がどうなっているのか確認してみます。

ルート確認

routes/auth.phpに導入された機能のルートがまとまっています。
これだけ用意してくれているんですね。。。

<?php

use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Auth\NewPasswordController;
use App\Http\Controllers\Auth\PasswordController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\Auth\RegisteredUserController;
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;

Route::middleware('guest')->group(function () {
    Route::get('register', [RegisteredUserController::class, 'create'])
                ->name('register');

    Route::post('register', [RegisteredUserController::class, 'store']);

    Route::get('login', [AuthenticatedSessionController::class, 'create'])
                ->name('login');

    Route::post('login', [AuthenticatedSessionController::class, 'store']);

    Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
                ->name('password.request');

    Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
                ->name('password.email');

    Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
                ->name('password.reset');

    Route::post('reset-password', [NewPasswordController::class, 'store'])
                ->name('password.store');
});

Route::middleware('auth')->group(function () {
    Route::get('verify-email', EmailVerificationPromptController::class)
                ->name('verification.notice');

    Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
                ->middleware(['signed', 'throttle:6,1'])
                ->name('verification.verify');

    Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
                ->middleware('throttle:6,1')
                ->name('verification.send');

    Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
                ->name('password.confirm');

    Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);

    Route::put('password', [PasswordController::class, 'update'])->name('password.update');

    Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
                ->name('logout');
});


ログイン機能を見てみる

認証の確認としてログイン機能を追ってみます。
AuthenticatedSessionControllerクラスを見てみましょう。
storeメソッドでログイン処理を行なっています。

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Inertia\Response;

class AuthenticatedSessionController extends Controller
{
    /**
     * Display the login view.
     */
    public function create(): Response
    {
        return Inertia::render('Auth/Login', [
            'canResetPassword' => Route::has('password.request'),
            'status' => session('status'),
        ]);
    }

    /**
     * Handle an incoming authentication request.
     */
    public function store(LoginRequest $request): RedirectResponse
    {
        $request->authenticate();

        $request->session()->regenerate();

        return redirect()->intended(RouteServiceProvider::HOME);
    }

    /**
     * Destroy an authenticated session.
     */
    public function destroy(Request $request): RedirectResponse
    {
        Auth::guard('web')->logout();

        $request->session()->invalidate();

        $request->session()->regenerateToken();

        return redirect('/');
    }
}

$request->authenticate();の部分ですね。
さらにこのメソッドをみていきましょう。

public function authenticate(): void
    {
        $this->ensureIsNotRateLimited();

        if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
            RateLimiter::hit($this->throttleKey());

            throw ValidationException::withMessages([
                'email' => __('auth.failed'),
            ]);
        }

        RateLimiter::clear($this->throttleKey());
    }

注目したいのはAuthファサードのattemptメソッドを使用しているところです。attemptメソッドはフォームからの認証試行を処理するために使用されます。これでログインできているんですね。

auth.phpの確認

最後に設定ファイルも確認しておきます。
ガードでセッションドライバーが設定され
プロバイダーではUserモデルをeloquentで取得されるように設定されているのがわかりました。

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],

...省略

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


便利な反面、内部がどうなっているか理解していないと思わぬとことでしっぺ返しをくらいそうですね。。。
実務では独自の認証にすることが多いものなのでしょうかね?気になります。

この記事が気に入ったらサポートをしてみませんか?