Laravelでマルチ認証を実装してみたのでメモする

2021.01.18

見出し画像

今回はマルチ認証を実装してみたので、自分用のメモとして書いていきます。

laravel7.x系です。

目次

  1. 大まかな流れ
  2. 実装前の準備
  3. モデル、マイグレーションファイルの作成
  4. ルーティングの設定
  5. コントローラーを複製
  6. ビューの複製
  7. ユーザー登録
  8. ログインやログアウトの設定
  9. ログインしていない状態
  10. ログイン後に/employee/loginにアクセス出来てしまう

すべて表示

大まかな流れ

実装前の準備

モデル、マイグレーションファイルの作成

ルーティングの設定

コントローラーを複製

ビューの複製

色々なリダイレクトの設定(ログイン、ログアウト)

employeeは新規登録する必要がない場合

っていう感じで実装していきます。途中でコードを変更したりしますが基本は上の流れで実装します。

実装前の準備

認証機能をlaravelに追加していきます。以下の2つのコマンドを実行します。

composer require laravel/ui

php artisan ui vue --auth

次はvue.jsを使えるようにしていきます。

npm install
npm run watch

npm run watchはサーバーを立ち上げる前に実行してもらえると大丈夫です。別タブでphp artisan serveをしてアクセスできるか確認していきましょう。

データベースも作成しておきましょう。

mysql -u root
create database データベース名;
exit

作成したアプリケーションのenvファイルも書き換えます。

DB_DATABASE=作成したデータベース名

最後にマイグレートしてuserを作成しましょう。

php artisan migrate
上がうまくいかなかったら
php arttisan migrate:fresh

ここまでで通常のユーザーが作成できました。

モデル、マイグレーションファイルの作成

ここから従業員(Employee)を作成していきます。-mでマイグレーションも作成。

php artisan make:model Employee -m

マイグレーションファイルの中身はuserのものと同じにします。モデルファイルも同様です。

 public function up()
   {
       Schema::create('employees', 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();
       });
   }
class Employee extends Authenticatable
{
   use Notifiable;

   protected $fillable = [
       'name', 'email', 'password',
   ];

   protected $hidden = [
       'password', 'remember_token',
   ];

   protected $casts = [
       'email_verified_at' => 'datetime',
   ];
}

記述できたら再度マイグレートを実行しましょう。

ルーティングの設定

意外と大事です。ルーティングの設定。

Route::prefix('employee')->namespace('Employee')->name('employee.')->group(function() {
   Auth::routes();
});

urlがemployeeから始まるものはここに集まります。

AuthRouteMethods.phpでAuthの処理が書かれています。後ほど細かい設定を加えます。

コントローラーを複製

今ターミナルでphp artisan route:listを実行してもemployeeのログインコントローラーがないよ!というエラーが出てしまうかと思います。なのでコントローラーを作っていきます。

controllersディレクトリにEmployeeディレクトリを作成し、その中にAuthディレクトリをコピーして持ってきます。

mkdir Employee   controllersディレクトリで実行
cp -r Auth Employee/

php artisan route:listでルートの状態を確認できます。

ビューの複製

次はviewファイルをemployeeディレクトリを作成しその中にauthディレクトリを複製していきます。

mkdir employee   viewsディレクトリで実行
cp -r auth employee/

上記が上手くいけばemployee以下にauthのフォルダが存在しているはずです。

ユーザー登録

まずはユーザーの登録からやっていきます。employee以下に作成されたauth/regsiter.blade.phpのform部分のactionを変更します。

変更前
<form method="POST" action="{{ route('register') }}">

変更後
<form method="POST" action="{{ route('employee.register') }}">

こうすることで先ほど設定したコントローラーにアクションが飛ぶようになります。

public function showRegistrationForm()
{
    return view('employee.auth.register');
}

現在はコピーして作っているのでemployee.auth.registerに飛んでもUserが作られるようになっています。その部分を変更していきましょう。

    // use App\User; 変更前
    use App\Employee; 変更後

    protected function create(array $data)
   {
       return Employee::create([
           'name' => $data['name'],
           'email' => $data['email'],
           'password' => Hash::make($data['password']),
       ]);
   }

ここまでの設定でEmployeeユーザーを作成することができます。

次はログイン後のリダイレクト先を変更します。

リダイレクト先の設定がされているのはコントローラーの$redirectToの設定を変更していきます。ここはRouteServiceProvider.phpファイルに設定されているのでこのファイルから変更していきます。

public const HOME = '/home';
public const EMPLOYEE_HOME = '/employee/home';

設定したEMPLOYEE_HOMEをコントローラーに書くことでリダイレクト先が変更されます。

protected $redirectTo = RouteServiceProvider::HOME; 変更前

protected $redirectTo = RouteServiceProvider::EMPLOYEE_HOME; 変更後

次はリダイレクトでアクセスするためのviewファイル、コントローラー、ルーティングの設定を行います。

Route::prefix('employee')->namespace('Employee')->name('employee.')->group(function() {
   Auth::routes();
   
   以下を追加
   Route::get('/home', 'EmployeeHomeController@index')->name('employee_home');
});

EmployeeHomeControllerはHomeControllerを元に作成していきます。

次はguardの設定です。employeeで登録されているユーザーだけがアクセスできる形にしていきます。

    
  'guards' => [
       'web' => [
           'driver' => 'session',
           'provider' => 'users',
       ],

       'employee' => [
           'driver' => 'session',
           'provider' => 'employees',
       ],

       'api' => [
           'driver' => 'token',
           'provider' => 'users',
           'hash' => false,
       ],
   ],
   
   'providers' => [
       'users' => [
           'driver' => 'eloquent',
           'model' => App\User::class,
       ],

       'employees' => [
           'driver' => 'eloquent',
           'model' => App\Employee::class,
       ],
   ],
   'passwords' => [
       'users' => [
           'provider' => 'users',
           'table' => 'password_resets',
           'expire' => 60,
           'throttle' => 60,
       ],

       'employees' => [
           'provider' => 'employees',
           'table' => 'password_resets',
           'expire' => 60,
           'throttle' => 60,
       ],
   ],

上記で設定したguardを使用するようにコントローラーにguardの記載を追加します。この設定を記載しないと、デフォルトのwebが効いてしまいます。

   use Illuminate\Support\Facades\Auth; この記載も必要になります
      
   protected function guard()
   {
       return Auth::guard('employee');
   } 

最後にビューファイルの設定です。

@extends('layouts.app')

@section('content')
<div class="container">
   <div class="row justify-content-center">
       <div class="col-md-8">
           <div class="card">
               <div class="card-header">Employee Dashboard</div>

               <div class="card-body">
                   @if (session('status'))
                       <div class="alert alert-success" role="alert">
                           {{ session('status') }}
                       </div>
                   @endif

                   You are logged in!
               </div>
           </div>
       </div>
   </div>
</div>
@endsection

これでユーザーを登録した後に/employee/homeにリダイレクトされるようになっていればオーケーです。

ログインやログアウトの設定

今のままでは同じlayouts.appを使ってしまっているので、ログアウトのパスが同じになってしまいます。なので新しいviewファイルを読み込むようにします。

layoutsフォルダの中にapp_employeeファイルを作成します。app_employeeで変更する点は全てのrouteのアクションにemployee.をつけることです。コスすることで飛んでいくコントローラーがemployeeになります。

ログイン後のリダイレクト先も変更しておきましょう。またguardメソッドとログインフォームのファイルを変更します。

/employee/auth/loginコントローラーのファイル

use Illuminate\Support\Facades\Auth;

protected $redirectTo = RouteServiceProvider::EMPLOYEE_HOME;

public function showLoginForm()
{
   return view('employee.auth.login'); ログインフォームのファイル
}

protected function guard(){
   return Auth::guard('employee'); employeeテーブルを参照してauthが使える
}

ここまでで、ログインした後に/employee/homeにリダイレクトされることと、ログアウトをすることが確認できます。

ログインしていない状態

ログインしていない状態で/employee/homeにアクセスすると/loginにリダイレクトされてしまうので、middlewareを設定していきます。

Authenticate.phpでisメソッドを使用して/employee/loginで飛んできた場合の処理を書きます。

   protected function redirectTo($request)
   {
       if (! $request->expectsJson()) {
           if($request->is('employee/*')) return route('employee.login');
           return route('login');
       }
   }

これで/employee/loginで飛んできた場合はemployee.loginに返されることになります。

ログイン後に/employee/loginにアクセス出来てしまう

ログイン後に/employee/loginにアクセスすると遷移出来てしまうので、EmployeeHomeController.phpに変更を加え、employeeの情報をRedirectIfAuthenticated.phpに伝えられるようにします。

   public function __construct()
   {
       $this->middleware('auth:employee')->except('logout');
   }
public function handle($request, Closure $next, $guard = null)
   {
       if (Auth::guard()->check()) return redirect(RouteServiceProvider::HOME);
       if (Auth::guard('employee')->check()) return redirect(RouteServiceProvider::EMPLOYEE_HOME);
       // 上2つは下のif文と同じ意味になる
       // if (Auth::guard()->check()) {
       //     return redirect(RouteServiceProvider::HOME);
       // } elseif(Auth::guard('employee')->check()) {
       //     return redirect(RouteServiceProvider::EMPLOYEE_HOME);
       // }

       return $next($request);
   }

$guard = nullで$guardの情報を受け取れるようにするのが大事です。情報を飛ばす側はmiddleware(‘auth:employee’)とすることでemployeeとして存在しているか確認できます。

また登録画面にもアクセス出来ないように、registerコントローラーにも記載を加えます。

   public function __construct()
   {
       $this->middleware('guest:employee');
   }

上記の設定で/loginへのアクセスの場合もemployeeでログインしている場合は/employee/homeにリダイレクトされるように設定できました。

employeeは新規登録する必要がない場合

employeeは誰でも新規登録出来てしまうと、誰でもemployeeに慣れてしまうので新規登録を必要としないバージョンの実装も追加していきます。

ルーティングを下記のように設定することで、registerやpasswordリセットなどの機能がなくなります。AuthRouteMethods.phpで確認することができます。

Auth::routes(['register' => false, 
                   'reset' => false,
                   'confirm' => false,
                   'verify' => false
               ]);
               

php artisan route:listを実行するとemployee.registerがなくなっていることが確認できるはずです。

app_employeeファイルの記載も変更します。

@if (Route::has('register')) 変更前

@if (Route::has('employee.register')) 変更後

registerのボタンが消えます。

パスワードのリセットリンクも不要になります。/employee/auth/loginファイル。

@if (Route::has('password.request')) 変更前

@if (Route::has('employee.password.request')) 変更後

forgot your password?の文字が消えます。

ここまで実装できたら今回は終了です。

参考にしたサイト

https://reffect.co.jp/laravel/laravel-multi-authentication-understand

ポイント

ルーティングの設定が大事。

viewファイルではrouteのアクションを変える必要がある。

コントローラーではguardやmiddlewareを設定してリダイレクトの処理などに対応する。

ログイン機能だけに絞ることも可能である。

まとめ

実装しながら、これは記事にしてしっかり振り返ろうと思いながら書いていました。

ポイントで紹介した以外だと、guardやmiddlewareの扱いの理解がまだ浅いと感じました。ここを理解出来れば認証機能の流れも理解が深まると思っています。

まだまだ勉強です。

今回はこんな感じで!

以上!