# 前言
學習一個框架, 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, 所以通常期限都很長
Laravel Sanctum 的 SPA 驗證機制是使用 token 還是 cookie?
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 的權限
賦予該 tokenserver: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 cookieXSRF-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 並給予所有權限
留言