Laravel Sanctum(API 認證系統)

介紹

Laravel Sanctum 是 Laravel 官方提供的一套簡潔且安全的 API 認證方案,主要用於 SPA(單頁應用)或行動裝置的簡單 API 驗證。

功能 說明
🔐 SPA 認證 使用 Cookie + Session,可防止 CSRF 攻擊
🧾 API Token 認證 發行個人存取憑證,適用於行動裝置或第三方應用
🔒 簡潔安全 不需實作複雜的 OAuth2 流程(如 Passport)
🎯 適用場景 Vue、React 等前端,或行動 App 使用 token 認證

安裝 Sanctum

composer require laravel/sanctum

# 發佈設定檔與遷移檔
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

設定 Sanctum

// 在 config/auth.php 中設定 guard(API 驗證時用)
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'sanctum' => [
        'driver' => 'sanctum',
        'provider' => 'users',
    ],
],

使用方式一:SPA 認證(基於 Cookie)

步驟說明:

  1. 前端先 GET /sanctum/csrf-cookie(設定 CSRF token)
  2. 再 POST /login 進行登入(使用 web guard)
  3. Laravel 會發下 Session Cookie
  4. 後續所有請求只要帶上 cookie 即可進行身份驗證

後端範例(routes/web.php):

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;

Route::post('/login', function (Request $request) {
    $credentials = $request->only('email', 'password');

    if (Auth::attempt($credentials)) {
        $request->session()->regenerate();
        return response()->json(['message' => '登入成功']);
    }

    return response()->json(['message' => '帳號或密碼錯誤'], 401);
});

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

前端注意事項:

  • 必須使用 withCredentials: true 發送請求
  • 第一個請求需呼叫 /sanctum/csrf-cookie
// Axios 登入範例(SPA)
await axios.get('/sanctum/csrf-cookie'); // 取得 CSRF token
await axios.post('/login', {
  email: '[email protected]',
  password: 'secret'
}, { withCredentials: true });

使用方式二:API Token 驗證(使用個人憑證)

產生 Token

$user = User::find(1);
$token = $user->createToken('my-token-name')->plainTextToken;

使用方式

# HTTP Header 加上:
Authorization: Bearer {token}
// routes/api.php
Route::middleware('auth:sanctum')->get('/profile', function (Request $request) {
    return $request->user();
});

Token 管理

// 刪除當前 token(登出單一裝置)
$request->user()->currentAccessToken()->delete();

// 刪除所有 token(登出所有裝置)
$request->user()->tokens()->delete();

Sanctum vs Passport 差異比較

項目 Sanctum Passport
輕量簡單
OAuth2 支援
適合 SPA
適合大型 API 認證 ⚠️(僅限簡單)
認證方式 Cookie / Token OAuth2 Token

Laravel Sanctum + Vue 實作教學

後端設定(Laravel)

安裝 Sanctum

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

修改 CORS 設定(config/cors.php)

'paths' => ['api/*', 'login', 'logout', 'sanctum/csrf-cookie'],

'allowed_origins' => ['http://localhost:5173'],
'supports_credentials' => true,

middleware 設定(config/api.php)

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

API 路由設定(routes/api.php)

use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

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

Route::post('/login', function (Request $request) {
    $credentials = $request->only('email', 'password');

    if (Auth::attempt($credentials)) {
        $request->session()->regenerate();
        return response()->json(['message' => '登入成功']);
    }

    return response()->json(['message' => '登入失敗'], 401);
});

Route::post('/logout', function (Request $request) {
    Auth::guard('web')->logout();
    $request->session()->invalidate();
    $request->session()->regenerateToken();

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

前端設定(Vue + Vite)

安裝 Axios

npm install axios

Axios 設定檔(src/axios.js)

import axios from 'axios';

const api = axios.create({
  baseURL: 'http://localhost:8000',
  withCredentials: true,
});

export default api;

Vue 登入 / 登出 / 使用者資料

LoginView.vue

<template>
  <div>
    <h2>登入</h2>
    <input v-model="email" placeholder="Email" />
    <input v-model="password" type="password" placeholder="密碼" />
    <button @click="login">登入</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import api from '../axios';

const email = ref('');
const password = ref('');

const login = async () => {
  await api.get('/sanctum/csrf-cookie');
  try {
    await api.post('/api/login', {
      email: email.value,
      password: password.value
    });
    alert('登入成功');
  } catch (err) {
    alert('登入失敗');
  }
};
</script>

UserView.vue

<template>
  <div>
    <h2>使用者資料</h2>
    <button @click="getUser">取得使用者</button>
    <pre>{{ user }}</pre>

    <button @click="logout">登出</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import api from '../axios';

const user = ref(null);

const getUser = async () => {
  const res = await api.get('/api/user');
  user.value = res.data;
};

const logout = async () => {
  await api.post('/api/logout');
  alert('已登出');
};
</script>

.env 設定

SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:5173

測試流程

  1. 使用 npm run dev 啟動 Vue 前端
  2. 進入登入頁輸入帳密
  3. 登入成功後呼叫 /api/user 驗證是否登入成功
  4. 測試 /api/logout 是否能成功登出