Sử dụng Guard để tạo multiple Authentication

Trong bài viết này tôi sẽ hướng dẫn các bạn customer guard để tạo multiple authentication trong laravel 9.

Laravel cung cấp cho chúng ta guard để có thể tạo multiple authentication cho nhiều bảng, trong bài viết này tôi sẽ tạo login cho 2 bảng Users và Admins.

Bây giờ chúng ta sẽ bắt đầu taọ authentication!.

Bước 1: Tạo model

Đầu tiên bạn cần phải tạo model như command dưới đây:

php artisan make:model Doctor -m

và nó được update như dưới đây

App\Model\Doctor.php

namespace App\Models;

use Illuminate\Support\Facades\Hash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;

class Doctor extends Authenticatable
{
    use HasFactory, Notifiable;
    
    protected $guarded = [];

    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = Hash::make($value);
    }

    public function scopeIsActive($query)
    {
        return $query->where('is_active',1);
    }
}

nội dung file migrate

public function up()
{
  Schema::create('doctors', function (Blueprint $table) {
      $table->id();
      $table->string('name');
      $table->string('email',32)->unique();
      $table->string('password',255);
      $table->boolean('is_active')->default(true);
      $table->timestamps();
  });
}

Bước 2: Tạo Guard

Trong bước này, chúng ta cần tạo tên bảo vệ tùy chỉnh của mình. Vì vậy, hãy truy cập theo đường dẫn config/auth.php và tạo tên guard của riêng bạn bao nhiêu tùy thích.

config/auth.php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session", "token"
    |
    */

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

        'doctor' => [
            'driver' => 'session',
            'provider' => 'doctors',
        ],

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

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

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

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'doctors' => [
            'provider' => 'doctors',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

Bước 3: Tạo Router

Bước này chúng ta sẽ tạo router theo từng guard cho các authentication

routes/doctor.php

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Doctor\Auth\LoginController;


Route::name('doctor.')->namespace('Doctor')->prefix('doctor')->group(function(){

    Route::namespace('Auth')->middleware('guest:doctor')->group(function(){
        //login route
        Route::get('/login','LoginController@login')->name('login');
        Route::post('/login','LoginController@processLogin');
    });

    Route::namespace('Auth')->middleware('auth:doctor')->group(function(){

        Route::post('/logout',function(){
            Auth::guard('doctor')->logout();
            return redirect()->action([
                LoginController::class,
                'login'
            ]);
        })->name('logout');

    });

});

Tiếp theo define nó trong RouteServiceProvider.php

app\Providers\RouteServiceProvider.php

namespace App\Providers;

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
 
    public const HOME = '/home';

    public const DOCTOR = '/doctor/home';

    protected $namespace = 'App\\Http\\Controllers';

    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));

           //our custom route path
            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/doctor.php'));
        });
    }

    protected function configureRateLimiting()
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
        });
    }
}

Bước 4: Tạo Controller

Bạn sẽ tạo một LoginController và define nó trong route.

App\Http\Controllers\Doctor\Auth\LoginController.php

namespace App\Http\Controllers\Doctor\Auth;

use Illuminate\Http\Request;
use Facades\App\Helper\Helper;
use App\Http\Requests\LoginRequest;
use App\Http\Controllers\Controller;
use App\Models\Doctor;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\View;
use App\Providers\RouteServiceProvider;
use Symfony\Component\HttpFoundation\Response;

class LoginController extends Controller
{   
    public function login()
    {
        if(View::exists('doctor.auth.login'))
        {
            return view('doctor.auth.login');
        }
        abort(Response::HTTP_NOT_FOUND);
    }

    public function processLogin(Request $request)
    {   
        $credentials = $request->except(['_token']);
        
        if(isDoctorActive($request->email))
        {
            if(Auth::guard('doctor')->attempt($credentials))
            {   
                return redirect(RouteServiceProvider::DOCTOR);
            }
            return redirect()->action([
                LoginController::class,
                'login'
            ])->with('message','Credentials not matced in our records!');
        }
        return redirect()->action([
            LoginController::class,
            'login'
        ])->with('message','You are not an active doctors!');
    }
}

sau đó tạo 1 filet helper viết hàm check tồn tại tài khoản để có thể sử dụng mọi nơi.

app\helper.php

use App\Models\Doctor;

if(!function_exists('isDoctorActive'))
{
    function isDoctorActive($email) : bool
    {   
        $doctor = Doctor::whereEmail($email)->isActive()->exists();

        return $doctor ? true : false;
    }
}

Bước 5: Tạo view


@extends('layouts.app')

@section('content')


   

       

           

               
{{ __('Doctor Login') }}

                @if(session()->has('message'))
                    {{ session()->get('message') }}
                @endif
               

                   

                        @csrf

 

                       


                            {{ __('E-Mail Address') }}

 

                           


                               

 

                                @error('email')
                                   
                                        {{ $message }}
                                   
                                @enderror
                           


                       

 

                       


                            {{ __('Password') }}

 

                           


                               

 

                                @error('password')
                                   
                                        {{ $message }}
                                   
                                @enderror
                           


                       

 

                       


                           

                               

                                   

 

                                   
                                        {{ __('Remember Me') }}
                                   
                               


                           

                       

 

                       


                           

                               
                                    {{ __('Login') }}
                               

 

                                @if (Route::has('password.request'))
                                   
                                        {{ __('Forgot Your Password?') }}
                                   

                                @endif
                           


                       

                   

               

           

       

   

@endsection