1
1

More than 1 year has passed since last update.

laravel学んで2か月で自サービスを開発した話 Part3

Last updated at Posted at 2022-03-01

みなさん、こんにちは。
早速ですが自サービスの開発記録3回目です。

今までの開発記録はこちらへ
胡蝶蘭を捨てるくらいならワイが欲しいので、サービス開発する編
公式ドキュメントの言う通り、パッケージをインストールされたら、Inertia.jsが導入されて???になった編

今回はマルチログインを実装します

ルートの設定

これも準備のところに入れるべきだったけど忘れてましたので、ここに記す
スクリーンショット (1643).png

Breezeをインストールした際にroutesフォルダにAuth.phpができているはず。
管理者用のルートとして、admin.phpを作成。
ユーザールートに使うweb.phpの内容とAuth.phpの内容をadmin.phpに貼り付け
前回でディレクトリ構成を変えたので、useの部分を変える
また、管理者のauthをしてしたいので、middleware(['auth:admin']) にする

admin.php
//ここから
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回 ライフサイクル編
numa_hamaru_man.png

Laravelの沼へようこそ

まずはapp/providers/RouteServiceProvider.phpを開く
ホームのURLがあるので、管理者用のホームを追加する

RouteServiceProvider.php
    public const HOME = '/dashboard';
    public const ADMIN_HOME='/admin/dashboard'; //追加

また、初期設定では、('/')が入力された場合、web.phpからルートを探す設定になっているので、
('admin')が入力された場合、admin.phpからルートを探すように追記する

RouteServiceProvider.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秒で説明してやる!
雑なGuardのイメージ.jpg
ただし、初期設定では一つしかないので増やします。
config/auth.phpへ行き、adminのguardを作ります。

auth.php
    '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へ

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へ

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へ

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フォルダに入っていた
スクリーンショット (1636).png
スクリーンショット (1642).png

をそれぞれのguardを使うように設定します
さすがに全部は書ききれないので、一例を

RegisteredUserController.php
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ように分ける

app.blade.php
<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などの知識を学べるため、やってみて価値はあると思う。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1