技術 7 分鐘閱讀

Laravel 認證系統實作:從基礎到進階

Laravel 認證系統實作:從基礎到進階

前言

認證系統是幾乎每個專案都需要的功能。Laravel 提供了非常完善的認證機制,這篇文章帶你從基礎的登入註冊到進階的 API Token 認證和權限管理。

Laravel Breeze:快速開始

如果是全新專案,用 Breeze 最快:

composer require laravel/breeze --dev
php artisan breeze:install react

npm install && npm run build
php artisan migrate

Breeze 會自動建立完整的認證頁面:註冊、登入、忘記密碼、Email 驗證。搭配 Inertia.js 和 React,前後端一次搞定。

Sanctum API 認證

如果你的前端是 SPA 或需要提供 API 給行動裝置使用,Sanctum 是最佳選擇。

安裝與設定

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

在 User Model 加入 Trait:

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

Token 認證

// 登入並發放 Token
class AuthController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        $user = User::where('email', $request->email)->first();

        if (!$user || !Hash::check($request->password, $user->password)) {
            return response()->json([
                'message' => '帳號或密碼錯誤',
            ], 401);
        }

        // 建立 Token,可設定權限
        $token = $user->createToken('api-token', ['read', 'write'])->plainTextToken;

        return response()->json([
            'user' => $user,
            'token' => $token,
        ]);
    }

    public function logout(Request $request)
    {
        // 撤銷當前 Token
        $request->user()->currentAccessToken()->delete();

        return response()->json([
            'message' => '已登出',
        ]);
    }
}

保護路由

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });

    Route::apiResource('products', ProductController::class);
});

SPA 認證(Cookie-based)

對於同網域的 SPA,可以使用 Cookie 認證,不需要管理 Token:

// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS',
    'localhost,localhost:3000,localhost:5173'
)),

前端在呼叫 API 前先取得 CSRF Cookie:

// 初始化 CSRF
await fetch('/sanctum/csrf-cookie', {
  credentials: 'include',
});

// 之後的 API 呼叫都會自動帶上 Cookie
const response = await fetch('/api/user', {
  credentials: 'include',
});

社群登入:Socialite

安裝

composer require laravel/socialite

Google 登入實作

// config/services.php
'google' => [
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => env('GOOGLE_REDIRECT_URL'),
],
// routes/web.php
Route::get('/auth/google', [SocialiteController::class, 'redirect']);
Route::get('/auth/google/callback', [SocialiteController::class, 'callback']);
class SocialiteController extends Controller
{
    public function redirect()
    {
        return Socialite::driver('google')->redirect();
    }

    public function callback()
    {
        $googleUser = Socialite::driver('google')->user();

        $user = User::updateOrCreate(
            ['email' => $googleUser->getEmail()],
            [
                'name' => $googleUser->getName(),
                'google_id' => $googleUser->getId(),
                'avatar' => $googleUser->getAvatar(),
                'password' => Hash::make(Str::random(24)),
            ]
        );

        Auth::login($user);

        return redirect('/dashboard');
    }
}

權限管理:Policy 與 Gate

定義 Policy

php artisan make:policy ProductPolicy --model=Product
class ProductPolicy
{
    public function update(User $user, Product $product): bool
    {
        return $user->id === $product->user_id;
    }

    public function delete(User $user, Product $product): bool
    {
        return $user->id === $product->user_id
            || $user->role === 'admin';
    }
}

在 Controller 中使用

public function update(Request $request, Product $product)
{
    $this->authorize('update', $product);

    $product->update($request->validated());

    return response()->json($product);
}

Gate 定義

適合不需要 Model 的權限判斷:

// app/Providers/AuthServiceProvider.php
Gate::define('manage-users', function (User $user) {
    return $user->role === 'admin';
});
if (Gate::allows('manage-users')) {
    // 管理者才能執行
}

密碼重設流程

Laravel 內建的密碼重設流程已經很完整。如果需要自訂:

// 自訂重設密碼的 Email 內容
class User extends Authenticatable
{
    public function sendPasswordResetNotification($token)
    {
        $url = config('app.frontend_url') . '/reset-password?token=' . $token;

        $this->notify(new ResetPasswordNotification($url));
    }
}

Email 驗證

class User extends Authenticatable implements MustVerifyEmail
{
    // 加上 MustVerifyEmail 介面
}

// 路由加上 verified middleware
Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
});

安全性注意事項

Rate Limiting

防止暴力破解登入:

// routes/api.php
Route::post('/login', [AuthController::class, 'login'])
    ->middleware('throttle:5,1'); // 每分鐘最多 5 次

Token 有效期

// config/sanctum.php
'expiration' => 60 * 24, // Token 24 小時後過期

敏感操作需要重新驗證

Route::middleware(['auth', 'password.confirm'])->group(function () {
    Route::delete('/account', [AccountController::class, 'destroy']);
});

結語

Laravel 的認證系統已經幫你處理了大部分的工作,從簡單的登入註冊到複雜的 API 認證和權限管理都有對應的解決方案。在接案專案中,善用這些內建功能可以省下大量開發時間,也能確保安全性。重要的是理解每個方案的適用場景,選擇最適合你專案的做法。

#Laravel #認證 #Sanctum #PHP
Thousand Lab

Thousand Lab