みなさん、こんにちは。
早速ですが自サービスの開発記録3回目です。
今までの開発記録はこちらへ
胡蝶蘭を捨てるくらいならワイが欲しいので、サービス開発する編
公式ドキュメントの言う通り、パッケージをインストールされたら、Inertia.jsが導入されて???になった編
今回はマルチログインを実装します
ルートの設定
これも準備のところに入れるべきだったけど忘れてましたので、ここに記す
Breezeをインストールした際にroutesフォルダにAuth.phpができているはず。
管理者用のルートとして、admin.phpを作成。
ユーザールートに使うweb.phpの内容とAuth.phpの内容をadmin.phpに貼り付け
前回でディレクトリ構成を変えたので、useの部分を変える
また、管理者のauthをしてしたいので、middleware(['auth:admin']) にする
//ここから
use App\Http\Controllers\Admin\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Admin\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Admin\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Admin\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Admin\Auth\NewPasswordController;
use App\Http\Controllers\Admin\Auth\PasswordResetLinkController;
use App\Http\Controllers\Admin\Auth\RegisteredUserController;
use App\Http\Controllers\Admin\Auth\VerifyEmailController;
//ここまでのディレクトリ構成を変更
//省略//
Route::get('/dashboard', function () {
return view('admin.dashboard');
})->middleware(['auth:admin'])->name('dashboard'); //ここをmiddleware(['auth:admin'])に
Route::get('/register', [RegisteredUserController::class, 'create'])
->middleware('guest:admin')
->name('register');
Route::post('/register', [RegisteredUserController::class, 'store'])
->middleware('guest:admin');
Route::get('/login', [AuthenticatedSessionController::class, 'create'])
->middleware('guest:admin')
->name('login');
Route::post('/login', [AuthenticatedSessionController::class, 'store'])
->middleware('guest:admin');
Route::get('/forgot-password', [PasswordResetLinkController::class, 'create'])
->middleware('guest:admin')
->name('password.request');
Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])
->middleware('guest:admin')
->name('password.email');
Route::get('/reset-password/{token}', [NewPasswordController::class, 'create'])
->middleware('guest:admin')
->name('password.reset');
Route::post('/reset-password', [NewPasswordController::class, 'store'])
->middleware('guest:admin')
->name('password.update');
Route::get('/verify-email', [EmailVerificationPromptController::class, '__invoke'])
->middleware('auth:admin') //ここをmiddleware(['auth:admin'])に
->name('verification.notice');
Route::get('/verify-email/{id}/{hash}', [VerifyEmailController::class, '__invoke'])
->middleware(['auth:admin', 'signed', 'throttle:6,1']) //ここをmiddleware(['auth:admin'])に
->name('verification.verify');
Route::post('/email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware(['auth:admin', 'throttle:6,1']) //ここをmiddleware(['auth:admin'])に
->name('verification.send');
Route::get('/confirm-password', [ConfirmablePasswordController::class, 'show'])
->middleware('auth:admin') //ここをmiddleware(['auth:admin'])に
->name('password.confirm');
Route::post('/confirm-password', [ConfirmablePasswordController::class, 'store'])
->middleware('auth:admin'); //ここをmiddleware(['auth:admin'])に
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
->middleware('auth:admin') //ここをmiddleware(['auth:admin'])に
->name('logout');
同様にユーザーのauthも指定するためにweb.phpとauth.phpの** middleware(['auth:users']) **にする
サービスプロバイダの設定
サービスブロバイダ?なにそれぇ?という人は、こちらへどうぞ。
Laravelの構成概念 第1回 ライフサイクル編
Laravelの沼へようこそ
まずはapp/providers/RouteServiceProvider.phpを開く
ホームのURLがあるので、管理者用のホームを追加する
public const HOME = '/dashboard';
public const ADMIN_HOME='/admin/dashboard'; //追加
また、初期設定では、('/')が入力された場合、web.phpからルートを探す設定になっているので、
('admin')が入力された場合、admin.phpからルートを探すように追記する
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::prefix('/')
->as('user.')
->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
//ここから
Route::prefix('admin')
->as('admin.')
->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/admin.php'));
//ここまで
});
}
guardの設定
さっきルート設定したとき、middleware('auth:admin') をしたと思う
これはmiddlewareにあるgaurdを読み込んで、指定されたguardに認証したもののみをルート案内をする
もし、違う場合なら指定されたページに飛ばされるシステムである。
これで、入力欄に直接ログイン後の情報を入力しても、guardが侵入を許さない便利な機能。
何言っているかよくわからないかって?1秒で説明してやる!
ただし、初期設定では一つしかないので増やします。
config/auth.phpへ行き、adminのguardを作ります。
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'users' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
※パスワードリセットの機能もわける場合はあらかじめcreate_admin_password_resetsテーブルを作りましょう
ミドルウェアの設定
guardの設定をしたので、認証外だった場合のリダイレクト先を指定する
admin関連からリダイレクトするならadminログインへ、user関連からリダイレクトをするならuserログインへ飛ばす
app/Http/Middleware/Authenticate.phpへ
class Authenticate extends Middleware
{
protected $user_route='user.login';
protected $admin_route='admin.login';
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
if (Route::is('admin.*')) {
return route($this->admin_route);
} else {
return route($this->user_route);
}
}
}
}
さっきから、認証外から認証内のページを入り込めないように設定したが、逆にログインしているユーザーがゲストページに直接にアクセスをしたときにも認証しているguardごとにそれぞれのホームページにリダイレクトをかけるように処理 ログアウトしろ
ということでapp/Http/Middleware/RedirectIfAuthenticated.phpへ
class RedirectIfAuthenticated
{
private const GURAD_USER='users';
private const GURAD_ADMIN='admin';
public function handle(Request $request, Closure $next, ...$guards)
{ //ガード認証がuserで入力したURLがuser/*ならユーザーのdashboardへリダイレクト
if (Auth::guard(self::GURAD_USER)->check() && $request->routeIs('user.*')) {
return redirect(RouteServiceProvider::HOME);
}
if (Auth::guard(self::GURAD_ADMIN)->check() && $request->routeIs('admin.*')) {
return redirect(RouteServiceProvider::ADMIN_HOME);
}
return $next($request);
}
}
リクエスト
入力された情報が、ユーザーか管理者のどちらのテーブルを参照すればいいか、リクエスト処理を設定する
app/Http/Requests/Auth/LoginRequest.phpへ
public function authorize()
{
return true; //ここがtrueになっているか確認する!
}
//略//
public function authenticate()
{
$this->ensureIsNotRateLimited(); //ルートによって使用するguardを決める
if ($this->routeIs('admin.*')) {
$guard='admin';
} else {
$guard='users';
}
//決められたguardによって対応するテーブルからアカウントを参照する
if (! Auth::guard($guard)->attempt($this->only('email', 'password'), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => __('auth.failed'),
]);
}
コントローラー、ビューの設定
laravelBreezeをインストールしたときのAuthフォルダに入っていた
をそれぞれのguardを使うように設定します
さすがに全部は書ききれないので、一例を
namespace App\Http\Controllers\Admin\Auth; //namespeaceをAdmin\Authに書き換え
use App\Http\Controllers\Controller; //userをAdmin\Authに書き換え
use App\Models\Admin; //RegisteredUserController.phpはモデルの読み込みが必要
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;
class RegisteredUserController extends Controller
{
/**
* Display the registration view.
*
* @return \Illuminate\View\View
*/
public function create()
{
return view('admin.auth.register'); //adminを追記
}
/**
* Handle an incoming registration request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:admins'], //読み込みテーブルをadminsにする
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = Admin::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'prefecture'=>$request->prefecture,
]);
event(new Registered($user));
Auth::login($user);
return redirect(RouteServiceProvider::ADMIN_HOME); //ここをADMIN_HOMEに
}
}
ファイルによって修正する部分が違うけれど、共通しているのは
- namespaceとuseの読み込みディレクトリの修正
- return view('admin.auth.〇〇')にする
- RouteServiceProvider::HOME)をADMIN_HOMEにUserのファイルはそのままでOK
- Auth::guard('admin')->logout(); に使用したguardを入力
続いてビューは
それぞれのファイルに{{ route('admin.login') }}のようにadmin(user)を追記
あとは認証しているguardによって、表示部分の切り替えができるようにする
その前にresources/views/layouts/navigation.blade.phpを複製し、user用とadminように分ける
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100">
//ここから
@if (auth('admin')->user())
@include('layouts.admin-navigation')
@elseif(auth('users')->user())
@include('layouts.user-navigation')
@endif
//ここまで
<!-- Page Heading -->
<header class="bg-white shadow">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8 bg-green-300">
{{ $header ?? '' }
</div>
</header>
<!-- Page Content -->
<main>
{{ $slot }}
</main>
</div>
これでマルチログインの設定は完了
終わりに
今回は初期からあったものとAdminのマルチログインの2つだけでしたが、10通りのマルチログインを切り分けることも可能だと思う なお保守
単一ログインでもECサイトを作ることは可能だけれど、マルチログインの導入はサービスブロバイダ,guard,middlewareなどの知識を学べるため、やってみて価値はあると思う。