Ray Lee | 李宗叡
Learn or Die
Published in
17 min readJan 21, 2021

--

Photo by 🐣 Luca Iaconelli 🦊 on Unsplash

# 版本

Laravel 8.x

# 前言

我喜歡使用 Laravel 開發的感覺, 除了開發快速, 程式碼簡潔且優雅之外, Laravel 框架本身也是一個很好的學習參照物。 本篇主要將官方文件重點整理成 Q&A 的形式呈現, 原子化的概念, 這方式並不適用於每個人, 但若對你有幫助, 我會很開心。

# 目錄

Laravel — 官方文件原子化翻譯 — 目錄

# 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 的權限 賦予該 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 並給予所有權限

--

--

Ray Lee | 李宗叡
Learn or Die

It's Ray. I do both backend and frontend, but more focus on backend. I like coding, and would like to see the whole picture of a product.