0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravel Sanctum セットアップしてみる

Posted at

概要

next.js・nginx・laravel・mysql環境で開発環境を立ち上げた際、初めてLaravel Sanctumを使ってみることにした。その際の手順を記します。

環境

        "php": "^8.2",
        "laravel/framework": "^12.0",
        "laravel/sanctum": "^4.0",

Sanctum の認証方式

Sanctum には 「SPA認証(クッキー方式)」「Token認証」 の2つの方法がある。

認証方式 説明 使用する機能
SPA認証(クッキー方式) フロントエンドとAPIが同じオリジン(localhost:3000localhost:8000 など)で動く場合に最適。ブラウザのセッションを利用する sanctum/csrf-cookie
Token認証 APIをモバイルアプリや外部サービスから使う場合に適している。ユーザーごとに発行したアクセストークンを使って認証する createToken()

今回の実装では、Token 認証を採用。

理由は、今後勉強のため外部APIサービスを導入する可能性があるから。

例えば、Stripe などの決済API、他のバックエンドサービスとの連携、モバイルアプリからのAPI利用 を想定すると、Token認証の方が適しているため、今回はこの方式を選択した。

Sanctum のセットアップ手順

  1. Sanctum をインストール

    composer require laravel/sanctum
    
  2. Sanctum の公開

    php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
    

    Sanctum の設定ファイルを config/sanctum.php にコピー する処理

  3. マイグレーションの実行

    php artisan migrate
    
  4. App\Models\UserHasApiTokens トレイトを追加

    use Laravel\Sanctum\HasApiTokens;
    
    class User extends Authenticatable
    {
        use HasApiTokens, HasFactory, Notifiable;
    }
    
  5. Sanctum のクッキー認証を有効にするための CORS 設定

    /config/cors.php

    <?php
    
    return [
        'paths' => ['api/*'], 
        'allowed_methods' => ['*'],
        'allowed_origins' => ['http://localhost:3000'],
        'allowed_origins_patterns' => [],
        'allowed_headers' => ['*'],
        'exposed_headers' => [],
        'max_age' => 0,
        'supports_credentials' => false,
    ];
    

    この設定ファイルは

    CORS(Cross-Origin Resource Sharing)

    のルールを管理するもの。

    フロントエンド(Next.js)とバックエンド(Laravel API)が

    異なるオリジン(ドメイン)

    で動作するとき、APIリクエストを許可するかどうかを決める。

    🔥 各設定の意味

    設定キー 役割 設定値 説明
    'paths' => ['api/*'] CORSを適用するAPIのパス ['api/*'] api/ 以下のすべてのAPIリクエストにCORSを適用する
    'allowed_methods' => ['*'] 許可するHTTPメソッド ['*'] GET, POST, PUT, DELETE などすべてのリクエストを許可
    'allowed_origins' => ['http://localhost:3000'] 許可するオリジン(アクセス元のドメイン) ['http://localhost:3000'] Next.js(フロントエンド)の開発サーバーからのリクエストを許可
    'allowed_origins_patterns' => [] 正規表現で許可するオリジン [] 特定のパターンを許可したい場合に使う(今回は未使用)
    'allowed_headers' => ['*'] 許可するリクエストヘッダー ['*'] すべてのヘッダー(Authorization, Content-Type など)を許可
    'exposed_headers' => [] クライアントがアクセスできるレスポンスヘッダー [] フロントエンド側で見えるレスポンスヘッダー(今回は未使用)
    'max_age' => 0 プリフライトリクエストのキャッシュ時間 0 0 にすると毎回プリフライトリクエストを送る
    'supports_credentials' => false クッキーを含めたリクエストを許可するか? false Token認証ではクッキーを使わないため false
  6. 仮でAPI設定

    /config/auth.php

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

    bootstrap/app.php

    <?php
    
    use Illuminate\Foundation\Application;
    use Illuminate\Foundation\Configuration\Exceptions;
    use Illuminate\Foundation\Configuration\Middleware;
    
    return Application::configure(basePath: dirname(__DIR__))
        ->withRouting(
            web: __DIR__.'/../routes/web.php',
            api: __DIR__.'/../routes/api.php', // ✅ これを追加して `routes/api.php` を有効化!
            commands: __DIR__.'/../routes/console.php',
            health: '/up',
        )
        ->withMiddleware(function (Middleware $middleware) {
            //
        })
        ->withExceptions(function (Exceptions $exceptions) {
            //
        })->create();
    
    

    Laravel 11 から routes/api.php がデフォルトでなくなったので、新規作成する必要がある

    routes/api.phpに仮でAPIを設定

    <?php
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
    use App\Http\Controllers\AuthController;
    
    Route::post('/login', [AuthController::class, 'login']);
    Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum');
    
    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
        return $request->user();
    });
    
    

    app/Http/Controllers/AuthController.php

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    use App\Models\User;
    
    class AuthController extends Controller
    {
        public function login(Request $request)
        {
            $credentials = $request->validate([
                'email' => 'required|email',
                'password' => 'required'
            ]);
    
            if (!Auth::attempt($credentials)) {
                return response()->json(['message' => 'Unauthorized'], 401);
            }
    
            $user = Auth::user();
            $token = $user->createToken('auth-token')->plainTextToken;
    
            return response()->json(['token' => $token, 'user' => $user]);
        }
    
        public function logout(Request $request)
        {
            $request->user()->tokens()->delete();
            return response()->json(['message' => 'Logged out']);
        }
    }
    
  7. テストしてみる

    適当にテストユーザーを作成

    database/seeders/DatabaseSeeder.php

    <?php
    
    namespace Database\Seeders;
    
    use App\Models\User;
    // use Illuminate\Database\Console\Seeds\WithoutModelEvents;
    use Illuminate\Database\Seeder;
    use Illuminate\Support\Facades\Hash;
    
    class DatabaseSeeder extends Seeder
    {
        /**
         * Seed the application's database.
         */
        public function run(): void
        {
            // User::factory(10)->create();
    
            User::factory()->create([
                'name' => 'Test User',
                'email' => 'test@example.com',
                'password' => Hash::make('password'),
            ]);
        }
    }
    
    
    php artisan db:seed
    

    tinkerで確認

    Psy Shell v0.12.7 (PHP 8.3.17  cli) by Justin Hileman
    > $user = \App\Models\User::first();
    $user->createToken('test-token')->plainTextToken;
    = "*********************"
    

    トークン作成はOK。

    リクエストしてみる

    curl -X POST http://localhost:8000/api/login \
         -H "Content-Type: application/json" \
         -d '{"email": "test@example.com", "password": "password"}'
    
    

    レスポンス

    {
    	"token": "*********************************",
    	"user": {
    		"id": 1,
    		"name": "Test User",
    		"email": "test@example.com",
    		"email_verified_at": "2025-03-08T05:42:05.000000Z",
    		"created_at": "2025-03-08T05:42:05.000000Z",
    		"updated_at": "2025-03-08T05:42:05.000000Z"
    	}
    }
    

    認証成功!

    認証確認

    % curl -X GET http://localhost:8000/api/user \
         -H "Authorization: Bearer {token}"
    

    結果

    {
    	"id": 1,
    	"name": "Test User",
    	"email": "test@example.com",
    	"email_verified_at": "2025-03-08T05:42:05.000000Z",
    	"created_at": "2025-03-08T05:42:05.000000Z",
    	"updated_at": "2025-03-08T05:42:05.000000Z"
    }
    

    OK!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?