Laravel multi auth with subdomain

  • September 9, 2023
  • 248

Thường chúng ta sẽ sử dụng multi auth with subpath để chia website thành các phần riêng biệt user, admin... Ngoài multi auth theo subpath chúng ta có thể sử dụng multi auth with subdomain. Multi auth with subdomain làm theo 2 cách sau:
Cách 1 đơn giản là code 2 repo độc lập cho user và admin, hoặc code 3 repo 1 api 2 repo frontend cho user và admin. Sau đó trỏ domain cho phần user và admin độc lập.
Cách 2 dùng 1 repo để tối ưu chi phí, sử dụng subdomain routing với laravel 10 jetstream inertia

Bài viết này chúng ta sẽ multi auth with subdomain sử dụng subdomain routing của laravel(theo cách 2). Các bảng và cách config multi auth giống bài viết multi auth with subpath. Chỉ khác biệt ở các phần liên quan đến config subdomian routing, init route, check auth và unit test.

Config subdomain routing

Thêm admin route routes/admin.php bằng cách khai báo trong App\Providers\RouteServiceProvider


if (CommonHelper::checkSubDomain()) {
     Route::domain('admin'. env('APP_URL'))
           ->middleware('web')
           ->group(base_path('routes/admin.php'));
} else {
     Route::middleware('web')
           ->group(base_path('routes/web.php'));
}

// CommonHelper
public function checkSubDomain()
    {
        $url = request()->getSchemeAndHttpHost();
        if (str_contains($url, 'http://admin.localhost')) {
            return true;
        }

        return false;
    }

Khi sử dụng subdomain route chúng ta sẽ gặp vấn đề nếu ở site user và admin dùng route giống nhau thì sẽ bị ghi đè route của nhau.
VD Đăng nhập admin bằng link: http://admin.localhost/login và đăng nhập user bằng link: http://localhost/login.

Để không bị ghi đè route cần kiểm tra nếu đang dùng subdomain thì khai báo route subdomain không thì khai báo route web. Ngoài ra khi sử dụng laravel jetstream đối với login site admin cần ignore router login mặc định của laravel jetstream đi để không bị ghi đè route bằng cách thêm code vào hàm register của AppServiceProvider


public function register(): void
    {
        if (CommonHelper::checkSubDomain()) {
            Fortify::ignoreRoutes();
        }
    }

khai báo admin route vẫn giống như bài trước


<?php

use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Admin\LoginController;
use App\Http\Controllers\Admin\HomeController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::name('admin.')->namespace('Admin')->group(function () {
    Route::middleware(['guest:admin'])->group(function () {
        Route::get('/login', [LoginController::class, 'index'])->name('login.index');
        Route::post('/login', [LoginController::class, 'store'])->name('login.store');
    });
    Route::group(['middleware' => ['auth:admin']], function () {
        Route::get('/home', [HomeController::class, 'index'])->name('home.index');
        Route::get('/logout', [LoginController::class, 'logout'])->name('logout');
    });
});

Middware Authenticate

Sửa lại middware authenticate để redirect về đúng site login của admin hay user khi người dùng chưa đăng nhập


<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
use App\Helpers\CommonHelper;

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     */
    protected function redirectTo(Request $request): ?string
    {
        if (CommonHelper::checkSubDomain()) {
            return $request->expectsJson() ? null : route('admin.login.index');
        }

        return $request->expectsJson() ? null : route('login');
    }
}

Unit test with subdomain

Khi viết unit test cho subdomain sẽ gặp vấn đề ở hàm checkSubDomain luôn trả về là site user. Để giải quyết vấn đề này mỗi khi viết test cho subdomain cần overwire lại route admin.


 public function test_page_no_login(): void
    {
        require base_path('routes/admin.php');
        $response = $this->get('http://admin.localhost/home');
        $response->assertRedirect('http://admin.localhost/login');
    }

Auth with subdomain

Các controller, view và cách run application vẫn giống với bài viết multi auth with subpath khi tái sử dụng code xong là có thể dùng multi auth với subdomain rồi nhé.

Đăng nhập vào các trang dành cho user qua link http://localhost:8000/login. Sau khi đăng nhập xong người dùng sẽ được chuyển hướng về trang http://localhost:8000/home. Những người dùng chưa đăng nhập truy cập vào trang home sẽ chuyển hướng về trang login.

Đăng nhập vào các trang dành cho admin qua link http://admin.localhost:8000/login. Khi user đăng nhập xong thì sẽ được chuyển hướng về trang http://admin.localhost:8000/home. User chưa đăng nhập sẽ chuyển về trang login của admin.

Tổng kết

Như vậy là chúng ta đã dùng được multi auth with subdomain sử dụng laravel. Cá nhân mình không thích sử dụng cách này vì phải control lại phần overwire route, tốt nhất khi sử dụng multi auth với subdomain nên tách làm 2 repo khác nhau cho admin và user. Thanks for reading...