この記事に書いてあること
マルチログイン認証の実装方法
利用バージョン
Laravel8
モデル&マイグレーションをつくる
管理者用のモデルとマイグレーションをつくる
※一般ユーザー用のモデルとマイグレーションはデフォルトで入っているものを利用
以下のコマンドを実行
php artisan make:model Admin -m
モデルの設定
app/Models/User.php
の中身をまるっとAdmin.php
にコピペ
クラス名の変更を必ずする
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
//クラス名変える
class Admin extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
//省略
}
マイグレーションをつくる
モデルと同じように、database/migrations/create_users_table.php
の中身をまるっと、create_admins_table.phpへコピペ
テーブル名の変更を必ずする
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAdminsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//テーブル名変更
Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//テーブル名変更
Schema::dropIfExists('admins');
}
}
テストデータをつくる
管理者と一般ユーザーのテストデータを作ります
以下コマンドでシーダーファイルを作成
php artisan make:seed MultiAuthTableSeeder
Seederファイル(テストデータの設定ファイル)が作成されるので中身を以下のように変更
<?php
namespace Database\Seeders;
use App\Models\Admin;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Database\Seeder;
class MultiAuthTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$init_users = [
[
'name' => '一般ユーザー',
'email' => 'user@test.com',
'password' => 'secret',
],
];
foreach($init_users as $init_user) {
$user = new User();
$user->name = $init_user['name'];
$user->email = $init_user['email'];
$user->password = Hash::make($init_user['password']);
$user->save();
}
$init_admins = [
[
'name' => '管理者',
'email' => 'admin@test.com',
'password' => 'secret',
],
];
foreach($init_admins as $init_admin) {
$admin = new Admin();
$admin->name = $init_admin['name'];
$admin->email = $init_admin['email'];
$admin->password = Hash::make($init_admin['password']);
$admin->save();
}
}
}
SeederファイルをDatabaseSeederに登録
public function run()
{
$this->call(MultiAuthTableSeeder::class);
}
以下のコマンドでテーブルとテストデータをデータベースに作成
php artisan migrate:fresh --seed
各モデルでログインできるように設定する
複数のログイン機能をつくるには、ガード・プロバイダ・モデルがそれぞれ必要になります。
ここら辺の説明はこちらの記事を参照ください。
モデルはさっき作ったので、ガードとプロバイダを追加していきます。
これらはconfig/auth.php
で管理されているので、そちらを編集していく。
<?php
return [
//省略
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
//追加
'users' => [
'driver' => 'session',
'provider' => 'users',
],
//追加
'admins' => [
'driver' => 'session',
'provider' => 'admins',
],
],
//省略
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
//追加
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
//省略
];
コントローラーをつくる
以下のコマンドを実行
artisan make:controller MultiAuthController
作成されたコントローラを以下のように変更
メソッドの役割
- showLoginForm():ブラウザでメールアドレスやパスワードを入力するページ
- showUserDashBoard():一般ユーザーログイン後のダッシュボード
- showAdminDashBoard():管理者ログイン後のダッシュボード
- login():ログイン画面からのフォーム入力情報送信先
- logout():ダッシュボードページからのログアウト情報送信先
LoginとLogoutメソッドの定義方法はドキュメントにそれぞれ記載があるので、それらをまるっとコピペしてます。
Loginメソッド
Logoutメソッド
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class MultiAuthController extends Controller
{
public function showLoginForm() {
return view('multi_auth.login');
}
public function showUserDashBoard() {
return view('multi_auth.userDashBoard');
}
public function showAdminDashBoard() {
return view('multi_auth.adminDashBoard');
}
/**
* 認証の試行を処理
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
$credentials = $request->only(['email', 'password']);
$guard = $request->guard;
if (Auth::guard($guard)->attempt($credentials)) {
$request->session()->regenerate();
return redirect($guard.'/dashboard');
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
}
/**
* ユーザーをアプリケーションからログアウトさせる
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('multi_login');
}
}
ビューをつくる
showLoginForm()の中で指定したビュー
<html>
<head>
<link href="https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
<form method="POST" action="multi_login">
@csrf
<div class="p-3">
@foreach ($errors->all() as $error)
<li class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-3">{{$error}}</li>
@endforeach
<label class="block">メールアドレス</label>
<input class="border rounded mb-3 px-2 py-1" type="text" name="email">
<label class="block">パスワード</label>
<input class="border rounded mb-3 px-2 py-1" type="password" name="password">
<label class="block">ユーザータイプ</label>
<select name="guard" class="border rounded px-2 py-1 mb-5">
<option value="">▼選択してください</option>
<option value="users">一般ユーザー</option>
<option value="admins">管理者</option>
</select>
<br>
<button class="bg-blue-500 text-white rounded px-3 py-2" type="submit">ログイン</button>
</div>
</form>
</body>
</html>
showUserDashBoard()の中で指定したビュー
<html>
<head>
<link href="https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
一般ユーザーのダッシュボード
<form method="POST" action="/multi_login/logout">
@csrf
<div class="p-3">
<button class="bg-blue-500 text-white rounded px-3 py-2" type="submit">ログアウト</button>
</div>
</form>
</body>
</html>
showAdminDashBoard()の中で指定したビュー
<html>
<head>
<link href="https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
管理者のダッシュボード
<form method="POST" action="/multi_login/logout">
@csrf
<div class="p-3">
<button class="bg-blue-500 text-white rounded px-3 py-2" type="submit">ログアウト</button>
</div>
</form>
</body>
</html>
ルートをつくる
ミドルウェアのauthは:に続けてコンフィグで設定したユーザー名を記載
自動的にそのユーザーのログインを判別してくれる
<?php
use Illuminate\Support\Facades\Route;
// マルチ認証
// ログイン
Route::get('multi_login', [\App\Http\Controllers\MultiAuthController::class, 'showLoginForm']);
Route::post('multi_login', [\App\Http\Controllers\MultiAuthController::class, 'login']);
// ログアウト
Route::post('multi_login/logout', [\App\Http\Controllers\MultiAuthController::class, 'logout']);
// ログイン後のページ
Route::prefix('users')->middleware('auth:users')->group(function(){
Route::get('dashboard', [\App\Http\Controllers\MultiAuthController::class, 'showUserDashBoard']);
});
Route::prefix('admins')->middleware('auth:admins')->group(function(){
Route::get('dashboard', [\App\Http\Controllers\MultiAuthController::class, 'showAdminDashBoard']);
});
ログインしていないときの強制リダイレクトをつくる
デフォルトだと、リダイレクト先が通常のログインページになっているので変更
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return 'multi_login';//変更
}
}
}
おしまい。
所感
認証の仕組みを俯瞰して理解すると簡単・シンプルに実装できました。
参考記事