Multiple Authentication trong Laravel 9
Vấn đề
Một web app thường thấy sẽ căn bản có hai phần. Phần CMS để admin sử dụng để quản lí những content của trang, phần app để cho người dùng sử dụng. Để thiết kế được một web app như trên, chúng ta sẽ thêm role vào user để có thể phân quyền, như vậy chúng ta chỉ sử dụng duy nhất 1 bảng table. Ví dụ như user có role là admin, staff hoặc writer thì sẽ có thể truy cập vào trong cms, nếu không thì sẽ chỉ có thể truy cập vào app. Tuy nhiên, nếu chúng ta muốn tách những người dùng sử dụng hệ thống và những nguời dùng app ra thành hai bảng riêng thì chúng ta sẽ authtenticate bằng cách nào? Cùng tìm hiểu nhé.
Sơ lược về app
Đây là một web app gồm 2 phần, CMS cho admin và phần app cho người dùng. Mình sẽ dùng model User cho admin và model Customer cho người dùng app.
Tùy chỉnh auth.php
Trước hết, chúng ta vào trong config/auth.php. Có 3 phần cần để ý để điều chỉnh đó là guards, providers và passwords. Nói sơ qua về 3 phần trên thì guards sẽ cần khai báo driver và provider. Driver hiện đang support là session, còn provider là tên provider mà chúng ta sẽ khai báo trong mục providers. Mình sẽ khai báo guards của mình như sau:
'guards' => [
...
'customer' => [
'driver' => 'session',
'provider' => 'customers',
],
],
Ở đây, mình đã thêm 1 guard tên là customer sử dụng driver session và provider là customers.
Tiếp đến là provider, trong provider chúng ta cần khai báo driver là database hoặc eloquent và model là model mà chúng ta sử dụng để authenticate. Mình sẽ khai báo provider của mình như sau:
'providers' => [
...
'customers' => [
'driver' => 'eloquent',
'model' => App\Models\Customer::class,
],
],
Lưu ý là trong phần guard, chúng ta đã khai báo là dùng provider tên customers thì trong phần khai báo này mình phải đặt tên là provider là customers để guard và provider có thể tìm thấy nhau.
'passwords' => [
...
'customers' => [
'provider' => 'customers',
'table' => 'customer_password_resets',
'expire' => 60,
'throttle' => 60,
],
],
Đảm bảo
Tiếp theo là chúng ta cần đảm bảo đã có migration để tạo những table cần thiết như customer, customer_password_resets. Đã khởi tạo model customer, model customer trong trường hợp này sẽ giống với model user và chỉ khác tên:
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class Customer extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Và đã có dữ liệu trong bảng customer.
Dùng guard mới chỉnh
Như vậy, chúng ta đã khai báo guard mới xong. Tiếp theo là cần sử dụng guard mới chỉnh này. Đơn giản là tìm đến nơi các bạn dùng Auth::atempt và thêm guard và truyền tham trị là tên guard vào. Ở đây mình dùng tên guard là customer nên mình sẽ có Auth::guard('customer')
Auth::guard('customer')->attempt($this->only('email', 'password'), $this->boolean('remember'))
Mình expect kết quả là khi mà gõ đúng email và password thì Laravel sẽ tạo cho mình một cái session sau đó redirect về lại trang dashboard. Bạn thử login vào và kiểm tra session sẽ thấy chúng ta đã tạo ra đuợc một session khi gõ đúng email và password. Xui thay, nó lại không tự redirect về lại trang dashboard của customer.
Vấn đề nằm ở việc chúng ta đã có session, đã redirect nhưng không pass qua vòng sơ khảo của middleware. Cùng xem route /dashboard có gì nhé:
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Nhìn hình ta thấy, muốn vào được dashboard thì cần phải qua 2 middleware, auth và verifed. Verified thì dùng để chắc chắn người dùng đã verify email, còn auth dùng để chắc chắc người dùng đã có danh tính trên trang web tức là đã đăng nhập vào. Có vẻ verified middleware không phải vấn đề vì account đã được verifed. Vậy thì chỉ còn lại middleware auth. Vấn đề nằm ở chỗ là nếu để auth không thì nó sẽ truyền tham trị rỗng vào guard, do đó, sẽ dùng guard mặc định vì nó không kiếm thấy guard nào trong danh sách guard của nó cả. Mà mặc định thì không phải customer nên đương nhiên là không thể dùng thông tin của customer để authenticate được. Do đó, việc cần là truyền tham số vào trong middleware này rằng là chúng ta muốn dùng guard tên là customer. Để truyền tham số vào middleware, chúng ta làm như sau:
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth:customer', 'verified'])->name('dashboard');
Test
Có vẻ ngon lành cành đào, cũng thử nào. Vào trang login, điền đúng email và password, nhấn login. Tada. Cần test thêm một cái nữa là lấy thông tin người dùng trong bảng user thử xem có authenticate được không. Mình expect là không vì với guard customer, mình chỉ muốn authenticate cho những người trong bảng customers thôi. Đây là thông tin user với id là 1. Sau khi điền email và password, nhấn login thì kết quả trả ra là không tìm thấy record này. Đúng như mình expect.
Lời kết
Đó là tất cả những gì cần làm để có thể multiple authentication trong Laravel. Nếu có câu hỏi nào thì mấy bạn comment bên dưới để mình trả lời nhé.
All Rights Reserved