【Laravel】マルチログイン機能を作ってみる(Laravel11, 10)
はじめに
Laravelを使ったマルチログイン機能を作りましょう。
管理者用のログイン画面を作り、ユーザーとは全く別のログイン機能を作ります。
更新履歴
- 2024/03/13 Laravel11対応
- 2023/06/12 公開
環境
- Laravel10
- PHP 8.2.3
- Laravel Framework 10.13.1
- Laravel11
- PHP 8.2.16
- Laravel Framework 11.0.3
設計
画面レイアウト設計
管理ログイン画面
管理トップ画面
テーブル定義
Migrationクラスで追加するadminsテーブル定義です。
テーブルレコード
Seederクラスで追加するadminsテーブルのレコードです。
id | name | password | created_at | updated_at |
---|---|---|---|---|
1 | admin_01 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
2 | admin_02 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
3 | admin_03 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
4 | admin_04 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
5 | admin_05 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
6 | admin_06 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
7 | admin_07 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
8 | admin_08 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
9 | admin_09 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
10 | admin_10 | admin | 2022-12-30 11:22:33 | 2022-12-31 23:58:59 |
データベース
各ファイル作成
Adminモデル及び、関連クラスを作成しましょう。
php artisan make:model Admin -mfs
# 以下が追加される
# app/Models/Admin.php
# database/factories/AdminFactory.php
# database/migrations/YYYY_MM_DD_hhmmss_create_admins_table.php
# database/seeders/AdminSeeder.php
Modelクラス
追加されたAdminモデルの親クラスを\Illuminate\Foundation\Auth\User
クラスに変更しましょう。
app/Models/Admin.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
-use Illuminate\Database\Eloquent\Model;
+use Illuminate\Foundation\Auth\User as Authenticatable;
-class Admin extends Model
+class Admin extends Authenticatable
{
use HasFactory;
}
テーブル作成準備
Migrationクラス
adminsテーブル定義をMigrationクラスのup
メソッドに記述しましょう。
追加済みのMigrationクラス(YYYY_MM_DD_HHmmss_create_admins_table.php
)のupメソッドに
nameカラムとpasswordカラムを追加します。
database/migrations/YYYY_MM_DD_HHmmss_create_admins_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('admins', function (Blueprint $table) {
$table->id();
+ $table->string('name')->unique()->comment('名称');
+ $table->string('password')->comment('パスワード');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('admins');
}
};
Seederクラス
adminsテーブルにレコード10件(name
がadmin_01
〜admin_10
、password
がadmin
)を追加するよう
Seeder::run メソッドに記述しましょう。
database/seeders/AdminSeeder.php
<?php
namespace Database\Seeders;
+use App\Models\Admin;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
+use Illuminate\Support\Facades\Hash;
class AdminSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
+ if (app()->isLocal()) {
+ // 開発環境のみレコードを追加
+ Admin::factory()
+ ->count(10)
+ ->sequence(function ($sequence) {
+ return [
+ 'name' => sprintf('admin_%02d', $sequence->index + 1),
+ 'password' => Hash::make('admin'), // パスワード: admin ※ 開発環境用のパスワードのためソース埋め込み
+ 'created_at' => '2022-12-30 11:22:33',
+ 'updated_at' => '2022-12-31 23:58:59',
+ ];
+ })
+ ->create();
+ }
}
}
database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
+ $this->call([
+ AdminSeeder::class,
+ ]);
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
}
}
テーブル作成
MigrationとSeederを実行をしましょう。
これにより、自動的にテーブル・レコードが作成されます。
# Running Migrations
php artisan migrate
# Running Seeders
php artisan db:seed
誤ってテーブルが作成してしまった場合
以下のコマンドを実行すると、全てのテーブルを削除し
再度、MigrationとSeederを実行します。
# 全テーブル初期化(全テーブル削除 → Migrations実行 → Seeders実行)
php artisan migrate:fresh --seed
ガードとプロバイダ設定
config/auth.php ファイルのプロバイダにadmins
、ガードにadmin
を追加しましょう。
これによりauth
ミドルウェアのadmin
ガード指定が可能になります。
config/auth.php
コメント部分は省略
<?php
return [
'defaults' => [
'guard' => env('AUTH_GUARD', 'web'),
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
+ 'admin' => [
+ 'driver' => 'session',
+ 'provider' => 'admins',
+ ],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
+ 'admins' => [
+ 'driver' => 'eloquent',
+ 'model' => App\Models\Admin::class,
+ ],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
];
Requestクラス
ログイン情報のバリデーションを行う、フォームリクエストを作成します。
php artisan make:request AdminLoginRequest
app/Http/Requests/AdminLoginRequest.php
以下のauthenticate
メソッドはControllerから
手動で呼び出すメソッドとして追加しています。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Validation\ValidationException;
class AdminLoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
- return false;
+ return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
*/
public function rules(): array
{
return [
- //
+ 'name' => 'required',
+ 'password' => 'required',
];
}
+
+ public function authenticate(): void
+ {
+ if (!Auth::guard('admin')->attempt($this->only('name', 'password'))) {
+ throw ValidationException::withMessages(['failed' => __('auth.failed')]);
+ }
+ }
}
__('auth.failed') は何をしている?
__
は言語ファイルから指定キーのメッセージを取得するヘルパ関数です。
lang/xx/auth.php
ファイルのfailed
キーのメッセージを取得しています。
参考
スターターキット Laravel Breeze の\App\Http\Requests\Auth\LoginRequest
クラスを参考にしています。
Routing・Middleware・View・Controller
ルート一覧
これから追加すルートの一覧です。
管理トップ画面は、管理ログイン後のみアクセス可能にします。
HTTPメソッド | URI | ルート名 | Controller@method | 機能 |
---|---|---|---|---|
GET | HEAD | admin | admin.top | - | 管理トップ画面🔑 |
GET | HEAD | admin-login | admin.login | AdminLoginController@create | 管理ログイン画面 |
POST | admin-login | admin.login.store | AdminLoginController@store | 管理ログイン |
DELETE | admin-login | admin.login.destroy | AdminLoginController@destroy | 管理ログアウト |
Controllerクラス生成
以下、コマンドでAdminLoginController
クラスを生成します。
php artisan make:controller AdminLoginController
Routing
ルート一覧通りにroutes/web.php
にルートを追記しましょう。
routes/web.php
以下を追記しましょう。
// 管理ログイン画面
Route::get('/admin-login', [AdminLoginController::class, 'create'])->name('admin.login');
// 管理ログイン
Route::post('/admin-login', [AdminLoginController::class, 'store'])->name('admin.login.store');
// 管理ログアウト
Route::delete('/admin-login', [AdminLoginController::class, 'destroy'])->name('admin.login.destroy');
// 管理ログイン後のみアクセス可
Route::middleware('auth:admin')->group(function () {
Route::get('/admin', function () {
return view('admin.top');
})->name('admin.top');
});
追記が終わったら、正常に設定できているか確認しましょう。
php artisan route:list
Middlewareクラス
ゲストアクセス時(ログインしていない場合)に、管理ログイン画面にリダイレクトするように追記します。
app/Http/Middleware/Authenticate.php (Laravel10の場合)
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*/
protected function redirectTo(Request $request): ?string
{
+ if (request()->routeIs('admin.*')) {
+ return $request->expectsJson() ? null : route('admin.login');
+ }
return $request->expectsJson() ? null : route('login');
}
}
bootstrap/app.php (Laravel11の場合)
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
+use Illuminate\Http\Request;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
+ $middleware->redirectGuestsTo(function(Request $request) {
+ if (request()->routeIs('admin.*')) {
+ return $request->expectsJson() ? null : route('admin.login');
+ }
+ return $request->expectsJson() ? null : route('auth');
+ });
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
Controllerクラス
AdminLoginControllerクラスにcreate
、store
、destroy
メソッドを追加しましょう。
app/Http/Controllers/AdminLoginController.php
<?php
namespace App\Http\Controllers;
+use App\Http\Requests\AdminLoginRequest;
+use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
class AdminLoginController extends Controller
{
- //
+ /**
+ * ログイン画面
+ */
+ public function create(): View
+ {
+ return view('admin.login');
+ }
+
+ /**
+ * ログイン
+ */
+ public function store(AdminLoginRequest $request): RedirectResponse
+ {
+ $request->authenticate();
+
+ $request->session()->regenerate();
+
+ return redirect()->intended(route('admin.top'));
+ }
+
+ /**
+ * ログアウト
+ */
+ public function destroy(Request $request): RedirectResponse
+ {
+ Auth::guard('admin')->logout();
+
+ $request->session()->invalidate();
+
+ $request->session()->regenerateToken();
+
+ return to_route('admin.login');
+ }
}
readouble.com - Laravel 10.x 認証 - ユーザーを手作業で認証する
readouble.com - Laravel 10.x 認証 - ログアウト
readouble.com - Laravel 10.x ヘルパ - route()
readouble.com - Laravel 10.x ヘルパ - to_route()
参考
スターターキット Laravel Breeze の\App\Http\Controllers\Auth\AuthenticatedSessionController
クラスを参考にしています。
View
admin.login
(admin/login.blade.php
)と
admin.top
(admin/top.blade.php
)を追加しましょう。
resources/views/admin/login.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>管理</title>
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
form {
text-align: right;
}
</style>
</head>
<body>
<main>
<form method="POST" action="{{ route('admin.login.store') }}">
@csrf
<div>
<label for="name">Name: </label>
<input type="text" id="name" name="name" required />
</div>
<div>
<label for="password">Password: </label>
<input type="password" id="password" name="password" required />
</div>
<div>
@error('failed')
<p style="color:red">{{ $message }}</p>
@enderror
<button type="submit">ログイン</button>
</div>
</form>
</main>
</body>
</html>
resources/views/admin/top.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>管理</title>
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
form {
text-align: right;
}
</style>
</head>
<body>
<main>
@auth('admin')
<p>ログイン中です。</p>
@endauth
<form method="POST" action="{{ route('admin.login.destroy') }}">
@method('DELETE')
@csrf
<button type="submit">ログアウト</button>
</form>
</main>
</body>
</html>
動作確認
以下の動作確認をしましょう。
- 管理トップ画面(
/admin
) にアクセス- 【expected】 管理ログイン画面(
/admin-login
) にリダイレクトされる
- 【expected】 管理ログイン画面(
- 管理ログイン画面(
/admin-login
) にて存在しない名称を入力して「ログイン」ボタンクリック
管理ログイン画面(/admin-login
) にて誤ったパスワードを入力して「ログイン」ボタンクリック- 【expected】 管理ログイン画面のログインボタンの上に「
These credentials do not match our records.
」のメッセージが表示される
(日本語の場合、「ログイン情報が登録されていません。
」)
- 【expected】 管理ログイン画面のログインボタンの上に「
- 管理ログイン画面(
/admin-login
) にて正しい情報(name: admin_01, password: admin)を入力して「ログイン」ボタンクリック- 【expected】管理トップ画面(
/admin
) に遷移する
- 【expected】管理トップ画面(
- 管理トップ画面(
/admin
) にて「ログアウト」ボタンクリック- 【expected】管理ログイン画面(
/admin-login
) に遷移し、再度、管理トップ画面(/admin
) にアクセスしても管理ログイン画面にリダイレクトされる
- 【expected】管理ログイン画面(
Discussion