laravelでユーザー・管理者を作ってみる
laravelでユーザ、管理者を作ったのでまとめてみる。
seederでのユーザ作成、登録・ログインの実装、ユーザー認証について記載します
バージョン
- laravel 12.0.1
 
マイグレーションとモデルファイル
Userテーブルの詳細は以下の通り
| カラム | 詳細 | 
|---|---|
| name | ユーザーの名前 | 
| ユーザーのメールアドレス | |
| password | ユーザーのパスワード | 
| icon | ユーザーのアイコン | 
| is_admin | 管理者かどうか | 
マイグレーションファイルは以下の通り
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');
    }
};
モデルファイルの設定
class User extends Authenticatable
{
    use HasFactory, Notifiable;
    // カラムの追加
    protected $fillable = [
        'name',
        'email',
        'password',
        'icon',
    ];
    // 管理者チェック
    public function isAdmin():bool
    {
        return $this->is_admin;
    }
}
$fillableによりカラムを追加することが可能になります
isAdmin()で管理者ユーザーかどうかをチェックします
以下を実行してマイグレーション
php artisan migrate
seederからのユーザー作成
ファクトリ
次にseederとfactoryでデモユーザーと管理者ユーザを作ってみる
まずはデモユーザーから
以下のコマンドでシーダー、ファクトリの作成
php artisan make:seeder UsersTableSeeder
php artisan make:factory UserFactory
ファクトリではユーザの名前やemailなどのダミーを作成してくれます
iconはシーダーで追加するのでパス
    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 | 
| メールアドレスを生成 | 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を登録します
class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call(UsersTableSeeder::class);  //追加
    }
}
これでseederを実行したときにUsersTableSeederが呼び出されるようになりました
UsersTableSeederには以下のように記載
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ファイルで指定したものを使います。
存在しなかった場合は第二引数を参照します。
最後に以下を実行してユーザー情報を登録します
php artisan config:clear   #envファイルを設定した場合
php artisan migrate:refresh --seed  
これで管理者、デモユーザーは作れました
ユーザー登録
バリデーション(フォームリクエスト)
次にユーザー登録の実装をします
まずは作成フォームのバリデーションを作ります
以下のコマンドでファイルを作成
php artisan make:request RegisterRequest
次に以下の内容をファイルに記載
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()でエラーを起こしたときのメッセージを返します
バリデーションルールについては以下を参照
コントローラ
次にコントローラを実装。
以下のコマンドでファイルを作成
php artisan make:controller 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については以下のようにする
<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をつけてください
これで以下のようにユーザ登録ができるようになりました

ログイン・ログアウト機能
バリデーション
次にログイン機能を実装します。
先ほど同様にまずはフォームリクエストから
ファイルを作成した後、以下を記載
    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文字以上、大文字・小文字・数字を含めてください',
        ];
    }
コントローラの作成
同様にファイルを作成した後に以下を記載
まずはログインのコントローラー
    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()でログイン失敗時のメッセージを表示
次にログアウトのコントローラー
    public function logout(Request $request):RedirectResponse
    {
        // ログアウト
        Auth::logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();
        return redirect()->route('auth.login');
    }
ログアウトとログインは両方ともPOSTを使ってルーティングしてください
これでユーザー登録、ログイン、ログアウトのすべてを作りました
ユーザー認証
一般ユーザー
最後にユーザー認証について。
まずは一般ユーザーの認証について
以下のコマンドでミドルウェアを作成します
php artisan make:middleware UserIsAuthenticated
php artisan make:middleware UserIsAdmin
次に以下の内容をミドルウェアに記載します
public function handle(Request $request, Closure $next): Response
{
    // ユーザがログインしていない場合はloginフォームにリダイレクト
    if (!Auth::check()) {
        return redirect()->route('auth.login');
    }
    // ログイン済みの人はそのままアクセス
    return $next($request);
}
Auth::check()でユーザーがログイン状態かチェックします
認証に失敗した場合はログイン画面へリダイレクトします
管理者認証
管理者かどうかチェックします
UserIsAdminに以下を記載
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に記載します
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の中に登録したファイルを記載します。
また、エイリアスでミドルウェアの名前を登録しときます
ルーティング
最後にミドルウェアを利用したルーティングの例です
// 下は未認証でも行けるページ
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