Laravel - Packages - Sanctum (官方文件原子化翻譯)

# 前言

學習一個框架, Ray 的想法是, 在深入理解底層實作的原理之前, 應該先知道這個框架的 使用方法; 先學習怎麼使用這個前人造的輪子, 再學習怎麼樣一個輪子。
所以本篇文章重點在於細讀官方文件, 並將內容理解後以 Q&A 的方式記錄下來, 加速學習以及查詢。



# Installation

以下的 Laravel example command 的意思是?
  • Example:

    composer require laravel/sanctum
    php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
    php artisan migrate
  • Answer:
    安裝 sanctum package, vendor publish 會將 sanctum 的 config file 以及 migration file 放到 application 的預設資料夾, 最後 migrate 建立 API token 會使用到的 table

    以下的 Laravel example code 的意思是?
  • Example:

    <?php
    'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
  • Answer:
    若要使用 sanctum 的驗證機制, 需在 app/Http/Kernel.php 中加入 sanctum 的 middleware


# Migration Customization

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    class AppServiceProvider extends ServiceProvider
    {
    public function register()
    {
    Sanctum::ignoreMigrations();
    }

    public function boot()
    {
    //
    }
    }
  • Answer:
    當使用 sanctum 時, 可在 AppServiceProvider 的 register() 中, 使用 Sanctum::ignoreMigrations(), 不使用 Sanctum 預設的 migration

以下的 Laravel example command 的意思是?
  • Example:

    php artisan vendor:publish --tag=sanctum-migrations
  • Answer:
    export sanctum 的 default migration



# Configuration

# Overriding Default Models

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;

    class PersonalAccessToken extends SanctumPersonalAccessToken
    {
    // ...
    }
  • Answer:
    透過 extends SanctumPersonalAccessToken, 可以自定義 sanctum 使用的預設 model

    以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use App\Models\Passport\PersonalAccessToken;
    use Laravel\Sanctum\Sanctum;

    public function boot()
    {
    Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
    }
  • Answer:
    在自定義完成 PersonalAccessToken model 之後, 在任何一個 service provider 的 boot() 中可以指定 Sanctum 使用這個 model



# API Token Authentication

Laravel Sanctum 中的 API token 是用來幹嘛的?

用來允許特定應用程式使用的 token, 所以通常期限都很長

cookie

可以使用 Sanctum 的 API token 機制來驗證 SPA 嗎?

不要, 因為 API token 期限都很長, 使用情境為允許特定應用程式使用的單獨 token


# Issuing API Tokens

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Laravel\Sanctum\HasApiTokens;

    class User extends Authenticatable
    {
    use HasApiTokens, HasFactory, Notifiable;
    }
  • Answer:
    當要使用 sanctum 的 API token 時, 需先 use HasPoiTokens trait, 以使用其 method

    以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Illuminate\Http\Request;

    Route::post('/tokens/create', function (Request $request) {
    $token = $request->user()->createToken($request->token_name);

    return ['token' => $token->plainTextToken];
    });
  • Answer:
    建立一個 sanctum API token, 並在存進資料庫前會先使用 sha256 hash, 可使用 plainTextToken 取得尚未 hash 前的 token 回傳, createToken() 的 parameter 為 token name, 想像當我們使用 Google API token 時, 會給 token 一個名字, 這樣才知道這個 token 是用在哪一個應用程式上

以下的 Laravel Sanctum example code 的意思是?
  • Example:

    <?php
    foreach ($user->tokens as $token) {
    //
    }
  • Answer:
    當使用 Sanctum 時, 可使用 HasApiTokens trait 取得 user 的所有 token



# Token Abilities

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    return $user->createToken('token-name', ['server:update'])->plainTextToken;
  • Answer:
    當使用 Sanctum 的 creatToken() 時, 可在 arg2 定義該 token 的權限
    賦予該 token server:update 的權限

以下的 Laravel Sanctum example code 的意思是?
  • Example:

    <?php
    if ($user->tokenCan('server:update')) {
    //
    }
  • Answer:
    當使用 Sanctum 時, 可使用 tokenCan() 來判斷該 token 的權限


# First-Party UI Initiated Requests

Laravel Sanctum 中, 如果 incoming request 是來自 first-party, 那 tokenCan() 會回傳?

always return true

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    return $request->user()->id === $server->user_id &&
    $request->user()->tokenCan('server:update')
  • Answer:
    當使用 Sanctum 預設驗證機制時, 所有來自 first-party 的 token 都會被 tokenCan() 判斷 true, 而在這樣的設定下, 如果我們要定義 first-party token 的權限時, 便可使用 Authorization Policy
    如果該 token 不是 first-party token, 那 tokenCan() 就會擋下, 如果該 token 是 first-party token 但擁有者並不符合定義的規則, 那 Authorization Policy 也會擋下


# Protecting Routes

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Illuminate\Http\Request;

    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
    });
  • Answer:
    使用 sanctum 的 middleware 來 protect routes


# Revoking Tokens

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    $user->tokens()->delete();

    $request->user()->currentAccessToken()->delete();

    $user->tokens()->where('id', $tokenId)->delete();
  • Answer:
    無效化 $user 的所有 token
    無效化當前 request 的 token
    無效化指定 token



# SPA Authentication

# Configuration

# Configuration Your First-Party Domains

以下位於 Sanctum 的 Laravel example code 的意思是?
  • Example:

    <?php
    'stateful' => explode(',', env(
    'SANCTUM_STATEFUL_DOMAINS',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1'
    )),
  • Answer:
    如果 request 來自被包含在 stateful option 內的 domain 或 ip, 那針對這些 request 的 response 會附有帶著 authentication token 的 cookie

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

    'api' => [
    EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
  • Answer:
    當使用 Sanctum 時, 在 api middleware group 內加入 Sanctum 的驗證 middleware, 確保就算來自於 first-party 的 request 是呼叫 API route, 也會收到 session cookies


# CORS & Cookies

當使用 Laravel Sanctum 時, 務必確認要回傳 Access-Control-Allow-Credentials 為 true, 需在哪個檔案中設定?

config/cors.php, 將 supports_credentials 設為 true

以下位於 config/cors.php 的 Laravel example code 的意思是?
  • Example:

    <?php
    'supports_credentials' => false,
  • Answer:
    response 回傳 Access-Control-Allow-Credentials 為 true

以下位於 config/session.php 的 Laravel example code 的意思是?
  • Example:

    <?php
    'domain' => '.domain.com',
  • Answer:
    讓 session cookie 支援所有的 subdomain

以下的 Axios example code 的意思是?
  • Example:

    axios.defaults.withCredentials = true;
  • Answer:
    若要 request 攜帶 cookie, 需打開 withCredentials


# Authenticating

# CSRF Protection

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    axios.get('/sanctum/csrf-cookie').then(response => {
    // Login...
    });
  • Answer:
    當使用 Laravel Sanctum 驗證 SPA 時, 要登入前應先呼叫 /sanctum/csrf-cookie 來啟動 CSRF protection, 之後 Laravel 會在每一次的 request, 在瀏覽器 set cookie XSRF-TOKEN, 這時如果使用 Axios, Angular HttpClient 則會自動地將 XSRF-TOKEN cookie 附加到 X-XSRF-TOKEN 來避免 CSRF


# Protecting Routes

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Illuminate\Http\Request;

    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
    });
  • Answer:
    使用 Sanctum middleware 來驗證通往該 route 的 request


# Authorizing Private Broadcast Channels

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    // routes/api.php
    Broadcast::routes(['middleware' => ['auth:sanctum']]);
  • Answer:
    使用 Sanctum SPA 來驗證 private / presence broadcast channels

以下的 Laravel Echo example code 的意思是?
  • Example:

    <?php
    window.Echo = new Echo({
    broadcaster: "pusher",
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    encrypted: true,
    key: process.env.MIX_PUSHER_APP_KEY,
    authorizer: (channel, options) => {
    return {
    authorize: (socketId, callback) => {
    axios.post('/api/broadcasting/auth', {
    socket_id: socketId,
    channel_name: channel.name
    })
    .then(response => {
    callback(false, response.data);
    })
    .catch(error => {
    callback(true, error);
    });
    }
    };
    },
    })
  • Answer:
    使用 custom Pusher authorizer, 讓 Pusher 使用 axios



# Mobile Application Authentication

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Validation\ValidationException;

    Route::post('/sanctum/token', function (Request $request) {
    $request->validate([
    'email' => 'required|email',
    'password' => 'required',
    'device_name' => 'required',
    ]);

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

    if (! $user || ! Hash::check($request->password, $user->password)) {
    throw ValidationException::withMessages([
    'email' => ['The provided credentials are incorrect.'],
    ]);
    }

    return $user->createToken($request->device_name)->plainTextToken;
    });
  • Answer:
    當需求是使用 Sanctum 驗證 Mobile Device, 並且 issue token 時, 可在驗證 email, password 之後, issue 一個 token, 並命名為 $request->device_name


# Protecting Routes

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
    });
  • Answer:
    使用 sanctum middleware 來 protect routes


# Revoking Tokens

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    $user->tokens()->delete();

    $user->tokens()->where('id', $tokenId)->delete();
  • Answer:
    刪除 $user 所有的 token
    刪除 $user 指定的 token



# Testing

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use App\Models\User;
    use Laravel\Sanctum\Sanctum;

    public function test_task_list_can_be_retrieved()
    {
    Sanctum::actingAs(
    User::factory()->create(),
    ['view-tasks']
    );

    $response = $this->get('/api/task');

    $response->assertOk();
    }
  • Answer:
    使用 Sanctum 的 testing feature, 透過 User factory 建立一個 user 並給予 view-tasks 的權限

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    Sanctum::actingAs(
    User::factory()->create(),
    ['*']
    );
  • Answer:
    使用 Sanctum 的 testing feature, 透過 User factory 建立一個 user 並給予所有權限

Laravel - Packages - Fortify Laravel - Digging Deeper - Helpers (官方文件原子化翻譯筆記)

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×