Laravel 11で認証機能を0から自作する 【Part.2 – ユーザー登録機能の実装】

Laravel 11で認証機能を0から自作する

前回の記事では認証機能の実装に必要な共通レイアウトやトップページ等の作成を行いました。

今回の記事はユーザー登録機能を0から実装する方法を解説していきます。

環境: PHP 8.3.10, Laravel Framework 11.20.0

ユーザー登録機能の実装

1. ユーザーモデルの確認

LaravelにはデフォルトでUserモデルが用意されています。このモデルは、ユーザー認証に関連するデータベーステーブルと連携するために使用されます。Userモデルは、LaravelのAuthenticatable (Illuminate\Foundation\Auth\User)クラスを継承しており、これによって認証用のモデルとして機能しています。

app/Models/User.php
https://github.com/laravel/laravel/blob/11.x/app/Models/User.php

2. usersテーブルのマイグレーション

次に、ユーザー情報を保存するためのテーブルがデータベースに存在するかを確認します。Laravelにはデフォルトでusersテーブルのマイグレーションファイルが用意されていますが、必要に応じて確認及び、調整を行ってください。

database/migrations/0001_01_01_000000_create_users_table.php
https://github.com/laravel/laravel/blob/11.x/database/migrations/0001_01_01_000000_create_users_table.php

こちらのマイグレーションファイルが正しく設定されていることが確認できたら、以下のようにマイグレーションコマンドを実行してテーブルを作成します。

php artisan migrate

3. ユーザー登録コントローラーの作成

ユーザー登録のためのコントローラークラス、RegisterControllerを作成します。

php artisan make:controller Auth/RegisterController

app/Http/Controllers/Auth/RegisterController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;

class RegisterController extends Controller
{
    /**
     * 登録フォームを表示する
     *
     * @return \Illuminate\View\View
     */
    public function showRegistrationForm()
    {
        return view('auth.register');
    }

    /**
     * 新しいユーザーインスタンスを作成し、保存する
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function register(Request $request)
    {
        // 1. リクエストのデータを検証する
        $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        // 2. 新しいユーザーを作成する
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        // 3. ユーザー登録イベントを発行する
        event(new Registered($user));

        // 4. ユーザーをログインさせる
        Auth::login($user);

        // 5. ダッシュボードページにリダイレクトする
        return redirect()->route('dashboard');
    }
}
RegisterController 各メソッドの詳細

showRegistrationFormメソッドでは/registerへのGETリクエストの際に登録フォームを表示します。

registerメソッドでは登録実行時の入力値の検証を行い、Userモデルを利用して新規ユーザーをusersテーブルに作成します。

registerメソッド内で、呼び出しているeventはLaravelのイベントリスナーという機能で、これにより別な場所で定義している例えばメール送信等の関連処理を呼び出すことができますが、現時点では実装を行いませんのでこちらはスキップしてOKです。

ユーザ作成完了後にAuthファサードと呼ばれる機能の一つであるAuth::login($user)を実行して、作成したユーザを自動的にログイン状態にします。

最後にリダイレクトを行いdashboardページを表示します。

Authファサードとは

Authファサードは認証システムを簡単に使えるようにしてくれるLaravelの標準機能で、アプリケーションでユーザーのログインやログアウトなどの操作を簡単に行うことができます。
裏側では、Illuminate\Auth\AuthManagerクラスを使用しており、認証に関するさまざまなメソッド(例えば、attemptloginlogout など)を提供しています。

4.コントローラ基底クラスの変更

Laravel 11から、コントローラクラスの基底クラスである、App\Http\Controllers\Controller のデフォルトの実装が変更されました。以前のバージョンまでは、このクラスは Illuminate\Routing\Controller を継承していましたが、Laravel 11では抽象クラスとして定義されています。

app/Http/Controllers/Controller.php (Laravel 11.x)
https://github.com/laravel/laravel/blob/11.x/app/Http/Controllers/Controller.php

<?php

namespace App\Http\Controllers;

abstract class Controller
{
    //
}

この変更により、Laravel 11のコントローラークラスでは、デフォルトで middleware メソッドを使用できなくなりました。そのため、ユーザー認証やアクセス制御を行う場合には、追加の設定や変更が必要になります。

先ほど作成したRegisterControllerを含め、これから実装していく各コントーラークラスでも認証処理に必要な機能を使用できるようにする必要があるため、今回はApp\Http\Controllers\Controllerの実装を以前のLaravel 10.xの内容に合わせます。

Laravel 10.xの実装内容

App\Http\Controllers\Controller (Laravel 10.x)
https://github.com/laravel/laravel/blob/10.x/app/Http/Controllers/Controller.php

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

class Controller extends BaseController
{
    use AuthorizesRequests, ValidatesRequests;
}

5. ユーザー登録フォームのテンプレート作成

ユーザー登録画面のフォームを以下に作成します。
resources/views/auth/register.blade.php

@extends('layouts.app')

@section('title', 'ユーザー登録')

@section('content')
    <h2 class="text-center mb-4">ユーザー登録</h2>
    <form method="POST" action="{{ route('register') }}">
        @csrf
        <div class="mb-3">
            <label for="name" class="form-label">ユーザー名</label>
            @error('name')
            <div class="text-danger">{{ $message }}</div>
            @enderror
            <input id="name" type="text" name="name" class="form-control" value="{{ old('name') }}" autofocus>
        </div>

        <div class="mb-3">
            <label for="email" class="form-label">メールアドレス</label>
            @error('email')
            <div class="text-danger">{{ $message }}</div>
            @enderror
            <input id="email" type="email" name="email" class="form-control" value="{{ old('email') }}">
        </div>

        <div class="mb-3">
            <label for="password" class="form-label">パスワード</label>
            @error('password')
            <div class="text-danger">{{ $message }}</div>
            @enderror
            <input id="password" type="password" name="password" class="form-control">
        </div>

        <div class="mb-3">
            <label for="password-confirm" class="form-label">パスワード確認</label>
            @error('password_confirmation')
            <div class="text-danger">{{ $message }}</div>
            @enderror
            <input id="password-confirm" type="password" name="password_confirmation" class="form-control">
        </div>

        <button type="submit" class="btn btn-primary w-100">登録</button>
    </form>
    <div class="mt-3 d-flex justify-content-center">
        <a href="{{ route('home') }}" class="btn btn-outline-secondary mx-2">トップページに戻る</a>
    </div>
@endsection

6. トップページへのリンク作成

前回作成したトップページにユーザー登録のリンクを追加しておきます。

resources/views/index.blade.php

@extends('layouts.app')

@section('title', 'トップページ')

@section('content')
    <h2 class="text-center mb-4">トップページ</h2>

    @auth
        <p class="text-center">ログイン中: {{ Auth::user()->name }}</p>
    @endauth

    <div class="d-flex justify-content-center">
        <a href="{{ route('register') }}" class="btn btn-outline-primary mx-2">ユーザー登録</a>
        @auth
            <a href="{{ route('dashboard') }}" class="btn btn-primary mx-2">ダッシュボード</a>
        @endauth
    </div>
@endsection

7. ルーティングの設定

前回作成済みのルーティング設定に今回作成したユーザー登録機能のルーティングを新たに追記します。

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\Auth\RegisterController;

// トップページのルート
Route::get('/', [HomeController::class, 'index'])->name('home');

// ダッシュボードのルート(ログインが必要)
Route::get('/dashboard', [HomeController::class, 'dashboard'])->middleware('auth')->name('dashboard');

// ユーザー登録のルート
Route::get('register', [RegisterController::class, 'showRegistrationForm'])->name('register');
Route::post('register', [RegisterController::class, 'register']);

実装が完了したら、ユーザー登録/registerにアクセスし、実際にユーザー登録の実行を行います。

登録完了後、ダッシュボードページ /dashboardへのリダイレクトと、usersテーブルに登録したユーザーが作成されていることを確認します。

ユーザー登録送信時のエラーメッセージの日本語対応については以下の記事にて補足しています。

【Laravel 11】バリデーションメッセージを日本語化する

Follow me!