🫠

laravelでユーザー・管理者を作ってみる

に公開

laravelでユーザ、管理者を作ったのでまとめてみる。
seederでのユーザ作成、登録・ログインの実装、ユーザー認証について記載します
バージョン

  • laravel 12.0.1

マイグレーションとモデルファイル

Userテーブルの詳細は以下の通り

カラム 詳細
name ユーザーの名前
email ユーザーのメールアドレス
password ユーザーのパスワード
icon ユーザーのアイコン
is_admin 管理者かどうか

マイグレーションファイルは以下の通り

xxxxxx_create_users_table.php
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('icon')->nullable();
            $table->boolean('is_admin')->default(false);
            $table->rememberToken();
            $table->timestamps();
        });

    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};

モデルファイルの設定

User.php
class User extends Authenticatable
{
    use HasFactory, Notifiable;
    // カラムの追加
    protected $fillable = [
        'name',
        'email',
        'password',
        'icon',
    ];

    // 管理者チェック
    public function isAdmin():bool
    {
        return $this->is_admin;
    }
}

$fillableによりカラムを追加することが可能になります
isAdmin()で管理者ユーザーかどうかをチェックします
以下を実行してマイグレーション

bash
php artisan migrate

seederからのユーザー作成

ファクトリ

次にseederとfactoryでデモユーザーと管理者ユーザを作ってみる
まずはデモユーザーから
以下のコマンドでシーダー、ファクトリの作成

bash
php artisan make:seeder UsersTableSeeder
php artisan make:factory UserFactory

ファクトリではユーザの名前やemailなどのダミーを作成してくれます
iconはシーダーで追加するのでパス

UserFactory.php
    public function definition(): array
    {
        return [
            'name' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'password' => Hash::make('password'),
        ];
    }

fake()の主要なメソッドをchatgptに書いてもらいました

メソッド 内容
name フルネームを生成 John Doe
firstName 名のみを生成 John
lastName 姓のみを生成 Doe
email メールアドレスを生成 john.doe@example.com
safeEmail 安全なドメイン付きメールアドレス jane.doe@example.org
unique()->email 重複しないメールアドレスを生成 user123@example.com
userName ユーザー名を生成 johndoe92
password パスワードを生成(文字列) secret123
sentence 一文のテキストを生成 Lorem ipsum dolor sit amet.
paragraph 複数文の段落を生成 Lorem ipsum dolor sit amet...
text 任意長のテキストを生成 Lorem ipsum dolor sit amet...
numberBetween 指定範囲の整数を生成 faker->numberBetween(1, 100) → 57
randomDigit 0〜9のランダムな数字を生成 7
randomFloat ランダムな小数を生成 faker->randomFloat(2, 1, 100) → 42.67
boolean 真偽値を生成 true / false
date 日付(Y-m-d)を生成 2025-04-29
dateTime DateTimeオブジェクトを生成 2025-04-29 14:23:10
dateTimeBetween 指定範囲内のDateTimeを生成 faker->dateTimeBetween('-1 year', 'now')
uuid UUIDを生成 550e8400-e29b-41d4-a716-446655440000
url URLを生成 https://example.com
imageUrl ダミー画像URLを生成 https://lorempixel.com/640/480/
phoneNumber 電話番号を生成 090-1234-5678
address 住所全体を生成 1234 Main St, Tokyo
postcode 郵便番号を生成 123-4567
city 市区町村名を生成 Shibuya
company 会社名を生成 Acme Inc.
jobTitle 職業名を生成 Software Engineer
word ランダムな単語を生成 apple
words 複数単語の配列を生成 ['apple', 'banana', 'cherry']
slug スラッグ形式の文字列を生成 example-post-title
regexify 正規表現にマッチする文字列を生成 faker->regexify('[A-Z]{5}[0-4]{3}')

seederの作成

まずはDatabaseSeeder.phpに作成したseederを登録します

DatabaseSeeder.php
class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call(UsersTableSeeder::class);  //追加
    }
}

これでseederを実行したときにUsersTableSeederが呼び出されるようになりました
UsersTableSeederには以下のように記載

UsersTableSeeder.php
class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        // userのシーダー作成。アイコンを追加
        User::factory()->count(5)->create(['icon' => 'icon.png']);
        // 管理者ユーザーの作成 存在しなかったら第二引数をデフォで使用
        User::create([
            'name' => env('ADMIN_USER','root'),
            'email' => env('ADMIN_EMAIL','root@sample.com'),
            'password' => Hash::make(env('ADMIN_PASSWORD','password')),
            'icon' => 'icon.png',
            'is_admin' => true,
        ]);
    }
}

User::factory()->count()で指定した数のダミーデータを作れるようになります
また管理者ユーザーはenvファイルで指定したものを使います。
存在しなかった場合は第二引数を参照します。

最後に以下を実行してユーザー情報を登録します

bash
php artisan config:clear   #envファイルを設定した場合
php artisan migrate:refresh --seed  

これで管理者、デモユーザーは作れました

ユーザー登録

バリデーション(フォームリクエスト)

次にユーザー登録の実装をします
まずは作成フォームのバリデーションを作ります
以下のコマンドでファイルを作成

php artisan make:request RegisterRequest

次に以下の内容をファイルに記載

Auth/RegisterRequest.php
use Illuminate\Validation\Rules\Password;
class RegisterRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'name' => 'required|string|min:1|max:10',
            'email' => 'required|email|string|unique:users',
            'password' => [
                'required',
                'confirmed',
                Password::min(8)->mixedCase()->numbers(),
            ],
            'icon' => 'nullable|image|mimes:jpeg,png,gif,jpg|max:2048',
        ];
    }

    public function messages(): array
    {
        return[
            'name.required' => '名前は必須です',
            'name.min' => '名前は1文字以上で入力してください',
            'name.max' => '名前は10文字以内で入力してください',

            'email.required' => 'メールアドレスは必須です',
            'email.email' => 'メールアドレスの形式が正しくありません',
            'email.unique' => '既に存在しているメールアドレスです',

            'password.required' => 'パスワードは必須です',
            'password.confirmed' => 'パスワードが一致しません',
            'password.min' => 'パスワードは8文字以上で入力してください',
            'password.mixed_case' => 'パスワードには大文字・小文字を含めてください',
            'password.numbers' => 'パスワードには数字を含めてください',

            'icon.image' => 'アイコンは画像ファイルを選択してください',
            'icon.mimes' => 'アイコンはjpeg,png,gif,jpgのいずれかの形式にしてください',
            'icon.max' => 'アイコンのサイズは2MB以下にしてください'
        ];
    }
}

authorize()はフォームを送信できる権限についてです。(デフォルトはfalseになっているので注意)
rules()にバリデーションについて定義します
基本的にはパラメータ => ルール1|ルール2|ルール3|...という感じ。
messages()でエラーを起こしたときのメッセージを返します
バリデーションルールについては以下を参照
https://laravel.com/docs/12.x/validation#rule-size

コントローラ

次にコントローラを実装。
以下のコマンドでファイルを作成

bash
php artisan make:controller RegisterController

次に以下の内容をファイルに記載

RegisterController
class RegisterController extends Controller
{
    public function register(RegisterRequest $request):RedirectResponse
    {
        // ユーザの作成。ファイルをアップロードしない場合、デフォルトで登録
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
            'icon' => $request->file('icon') ? $request->file('icon')->store('icons','public') : 'images/default-icon.png'
        ]);

        // ユーザーイベントの発火。メール認証などしたいときに使う
        event(new Registered($user));

        // ユーザをログイン状態にする
        Auth::login($user);

        // ホームページにリダイレクト
        return redirect()->route('app.home');
    }
}

先ほどのモデルファイルで$fillableをつけておかないとエラーになります
viewは省略しますがpasswordについては以下のようにする

register.blade.php
<div>
    <label for="password">パスワード</label>
    <input type="password" name="password" id="password">
</div>
<div class="mb-4 flex flex-col sm:flex-row items-center gap-2">
    <label for="password_confirmation">パスワード再確認</label>
    <input type="password" name="password_confirmation" id="password_confirmation">
</div>

バリデーションでパスワードについてはconfirmedをつけたのでパスワードが一致する必要がありますがその際の確認用のパスワードのname属性はpassword_confirmationをつけてください
これで以下のようにユーザ登録ができるようになりました

ログイン・ログアウト機能

バリデーション

次にログイン機能を実装します。
先ほど同様にまずはフォームリクエストから
ファイルを作成した後、以下を記載

LoginRequest.php
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'email' => 'required|email',
            'password' => [
                'required',
                Password::min(8)->mixedCase()->numbers(),
            ]
        ];
    }

    public function messages(): array
    {
        return[
            'email.required' => 'メールアドレスは必須です',
            'email.email' => 'メールアドレスの形式が正しくありません',

            'password.required' => 'パスワードは必須です',
            'password.min' => 'パスワードは8文字以上で入力してください',
            'password.*' => 'パスワードは8文字以上、大文字・小文字・数字を含めてください',
        ];
    }

コントローラの作成

同様にファイルを作成した後に以下を記載
まずはログインのコントローラー

LoginController.php
    public function login(LoginRequest $request)
    {
        // emailとpasswordを取得
        $credentials = $request->only('email','password');

        // 受け取ったパラメータから認証する
        if (Auth::attempt($credentials)) {
            // セッションを再度生成し、リダイレクト
            $request->session()->regenerate();
            return redirect()->route('app.home');
        }
        // ログインに失敗した時
        return back()->withErrors([
            'email' => 'メールアドレスまたはパスワードが違います'
        ]);
    }

Auth::attempt()でログインを試みます。
withErrors()でログイン失敗時のメッセージを表示
次にログアウトのコントローラー

LogoutController.php
    public function logout(Request $request):RedirectResponse
    {
        // ログアウト
        Auth::logout();

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

        return redirect()->route('auth.login');
    }

ログアウトとログインは両方ともPOSTを使ってルーティングしてください
これでユーザー登録、ログイン、ログアウトのすべてを作りました

ユーザー認証

一般ユーザー

最後にユーザー認証について。
まずは一般ユーザーの認証について
以下のコマンドでミドルウェアを作成します

bash
php artisan make:middleware UserIsAuthenticated
php artisan make:middleware UserIsAdmin

次に以下の内容をミドルウェアに記載します

UserIsAuthenticated.php
public function handle(Request $request, Closure $next): Response
{
    // ユーザがログインしていない場合はloginフォームにリダイレクト
    if (!Auth::check()) {
        return redirect()->route('auth.login');
    }
    // ログイン済みの人はそのままアクセス
    return $next($request);
}

Auth::check()でユーザーがログイン状態かチェックします
認証に失敗した場合はログイン画面へリダイレクトします

管理者認証

管理者かどうかチェックします
UserIsAdminに以下を記載

UserIsAdmin.php
public function handle(Request $request, Closure $next): Response
{
    // 管理者でない場合はログインは認証されているのでhomeへリダイレクト!
    if (!Auth::user()->isAdmin()) {
        return redirect()->route('app.home');
    }
    return $next($request);
}

Userモデルに追加したisAdmin()で管理者かどうかをチェックします
adminミドルウェアはauthミドルウェアの後に通過するので認証に失敗した場合はhomeへリダイレクトしときます。

ミドルウェアの追加

次にミドルウェアを登録します
laravel-11以前はKernel.phpというファイルらしい
現バージョンではbootstrapフォルダのapp.phpに記載します

bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            'auth' => UserIsAuthenticated::class,
            'admin' => UserIsAdmin::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

withMiddlewareの中に登録したファイルを記載します。
また、エイリアスでミドルウェアの名前を登録しときます

ルーティング

最後にミドルウェアを利用したルーティングの例です

routes/web.php
// 下は未認証でも行けるページ
Route::prefix('auth')->group(function(){
    Route::get('/register',[RegisterController::class,'showRegisterView'])->name('auth.register');
    Route::post('/register',[RegisterController::class,'register']);
    Route::get('/login',[LoginController::class,'showLoginForm'])->name('auth.login');
    Route::post('/login',[LoginController::class,'login']);
});

// ユーザー認証を突破したひとが入れるページ
Route::middleware('auth')->prefix('app')->group(function(){
    Route::get('home',[HomeController::class,'showHomeView'])->name('app.home');
});

// ユーザー認証を突破し、管理者認証も突破したユーザーが入れるページ
Route::middleware('auth','admin')->prefix('admin')->group(function(){
    Route::get('/',[PartController::class,'showPartsView'])->name('admin.home');
});

最後に

これにて終了です
ユーザー認証、登録について自分なりにまとめてみました
ユーザ認証がバージョン11で大きく変わっていて調べるのに苦労しました🥹

Discussion