Laravel Multi Table Authentication
Tags: webdev, laravel, authentication, php
Published: 2023-02-07 10:06:48

Authentication is an essential component of any web application, and Laravel makes it easy to implement with its built-in authentication features powered by single user table. However what if you have multiple user types, each with its own table in the database? In this scenario, you need to implement multiple table authentication to ensure that the correct user is authenticated and given the right access to the application. 

In this article, I will walk you through the steps of implementing multiple table authentication in Laravel, so you can secure your application and give your users the best experience possible. Get ready to dive into the world of Laravel multiple table authentication!

Shall we? Let's go. 

I am starting with assumption that you know how to install a fresh laravel application and you have one installed already. That said, let us proceed.

Laravel comes with default users table, lets assume this is the table for default users of your application. And you want another table for admin users. 

### Model(s)
First we create model for the new class of users in this cas Admins. In your case it could be teachers and students. 
```
php artisan make:model Admin/Admin
```

Now you have created the Admin model, go in side it and replicate the following code. The Notifiable trait makes it possible to use laravel default notification on these model.

```
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class Admin extends Authenticatable
{
    use HasFactory, Notifiable;
    protected $guard = 'admin';
}    
```

### Configurations

Laravel have config folder that houses all config files. Inside this file, open auth.php file and paste the following code where we create authentication rules for admin.

In auth.php config

```
'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],
 'admin'=>[
        'driver'=>'eloquent',
        'model'=>App\Models\Admin\Admin::class,
     ],
  
```

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

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
        'admin'=>[
           'driver'=>'session',
           'provider'=>'admins',
        ],
    ],

```

```
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        'admins'=>[
            'driver'=>'eloquent',
            'model'=>App\Models\Admin\Admin::class,
         ],
    ],
```

```
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'admins'=>[
            'driver'=>'eloquent',
            'model'=>App\Models\Admin\Admin::class,
        ],
    ],
```

### Middleware

Now navigate to middlware folder and open the Authentication.php file. This is the file that redirect users who are not authenticated when they try accessing guarded pages. Notice that I commented out the default code in the file.

Middelware Authenticate.php
```
  // foreach ($guards as $guard) {
        //     if (Auth::guard($guard)->check()) {
        //         return redirect(RouteServiceProvider::HOME);
        //     }
        // }

         
        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {

                if($guard === 'admin'){
                    return redirect()->route('admin.home');
                }
                return redirect()->route('user.home');
                // return redirect(RouteServiceProvider::HOME);
            }
        }
    if (! $request->expectsJson()) {
            if($request->routeIs('admin.*')){
                return route('admin.login');
            }
            return route('login');
        }
```

In same middleware folder, open the following file. It is the middleware responsible for redirecting authenticated users based on the guard used in their authentication.

In RedirectIfAuthenticated.php
```
  // foreach ($guards as $guard) {
        //     if (Auth::guard($guard)->check()) {
        //         return redirect(RouteServiceProvider::HOME);
        //     }
        // }

         
        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {

                if($guard === 'admin'){
                    return redirect()->route('admin.home');
                }
                return redirect()->route('user.home');
                // return redirect(RouteServiceProvider::HOME);
            }
        }

```


### Admin auth controller
Here we shall create a controller to handle authentication for this category of users.

We begin by creating a controller to handle admin login.

```
php artisan make:controller Auth/AdminAuthController
```

Inside the controller

```
public function __construct()
{
     Auth::setDefaultDriver('admin');
     config(['auth.defaults.passwords' => 'admins']); 
}

public function login()
{
     return view('admin_auth.adminlogin');
}

   public function logoutAdmin(Request $request)
    {
        Auth::guard('admin')->logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();
        return redirect('/');
    }

public function store(Request $request)
{
     $request->validate([
         'email'=>'required|string',
         'password'=>'required|min:5|max:30'
      ]);

       
    if (Auth::guard('admin')->attempt(['email' => $request- 
    >identifier, 'password' => $request->password])|| 
     Auth::guard('admin')->attempt(['username' => $request>identifier, 'password' => $request->password])) {
            // Authentication was successful...
            return redirect()->route('panel');
     }
   else{
       return redirect()->route('admin.login')- 
         >with('fail','Incorrect credentials');
     }
    }

```


### Routes
Now let use create authentication logic for this set of users(admins). 

```
Route::get('/admin/login', [AdminAuthController::class, 'login'])->name('admin.login');
Route::get('/admin/login', [AdminAuthController::class, 'store'])->name('admin.login.store');
Route::post('/admin/logout', [AdminAuthController::class, 'logoutAdmin'])->name('admin.logout');

```
Pay attention to this part. You will need a route more leading to your dashboard or any other protected pages. **Below is exampme of such route. Notice the middleware usage auth:admin. Very important.**

```
Route::get('/panel', [AdminPagesController::class, 'panel_home'])->name('panel')->middleware('auth:admin');
```

### Login html
At this point, let us create blade file or html file for login admin login page. resources\views\admin_auth.blade.php 
Take note of where we are submitting this form to.

```
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  </head>
  <body>
    <!-- <h1>Hello, world!</h1> -->
    <main class="container mt-5">
    <form method="POST" action="{{route('admin.login.store')}}">
        @csrf 
        <div class="form-group">
            <h3 class="text-center">Admin Login</h3>
        </div>
        <div class="mb-3">
            <label for="exampleInputEmail1" class="form-label">Email or Username</label>
            <input type="text" class="form-control" name="identifier" id="exampleInputEmail1" aria-describedby="emailHelp">
            <div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
        </div>
        <div class="mb-3">
            <label for="exampleInputPassword1" class="form-label">Password</label>
            <input type="password" name="password" class="form-control" id="exampleInputPassword1">
        </div>
        <div class="mb-3 form-check">
            <input type="checkbox" name="remember" class="form-check-input" id="exampleCheck1">
            <label class="form-check-label" for="exampleCheck1">Check me out</label>
        </div>
        <button type="submit" style="float:right;" class="btn btn-primary">Submit</button>
    </form>
    </main>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
  </body>
</html>
```


### Migration
Now let us create table or migration for this new users - admins. Run the command 

```
php artisan make:migration create_admins_table 
```

Inside the migration file, copy and paste the code below

```
     $table->string('name');
     $table->string('username')->nullable();
     $table->string('email')->unique();
     $table->timestamp('email_verified_at')->nullable();
     $table->string('password');
     // $table->enum('admin_typ', ['admin'])->nullable();
     $table->rememberToken(); 
```


### Factory and Seeder 
Let us now quickly populate the database. We begin by making a model factory for our admin model and also a seeder file.

```
php artisan make:factory Admin/AdminFactory    
php artisan make:seeder AdminSeeder
```
Inside the factory Definition method

```
  return [
            'name' => fake()->name(),
            'username'=>fake()->userName(),
            'email' => fake()->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password'=>'$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
```

Inside the seeder file, in the run method

```
    \App\Models\Admin\Admin::factory(5)->create();

        \App\Models\Admin\Admin::factory()->create([
            'name' => 'Test Admin',
            'username'=>'admin',
            'email' => 'admin@admin.com',
        ]);
```
Next run the seeder command to populate your database. 

```
php artisan db:seed --class=AdminSeeder
```

Remember to create html blade for your protected page.

So that is it. Start your laravel application and try logging in on your admin login page.

**I am Vincent Ikechukwu, Full Stack Web Developer and Software Engineer.** Connect with me on social media via links below.

* Linkedin [Vincent](https://www.linkedin.com/in/ikechukwu-vincent-002934176/)
* Facebook [Vincent](https://web.facebook.com/ikechukwu.unegbu.14)
* Twitter [Vincent](https://twitter.com/TheV_Exe) 
* Github [Vincent](https://github.com/Ikechukwu-Unegbu/) 

If you run into trouble leave a comment or say hi on my social media.