可以請你解釋一下 passport 背後的機制嗎?(一)


前言

{{ 警告 }}
這個系列的文章都不保證正確

等等...不保證正確還敢發文!?

發文的用意有兩個:
1.作者想複習,順便記錄
2.坐等寫錯了有人看不下去跳出來打臉

正文開始

php artisan make:auth // 建立 view 和 web router
composer require laravel/passpor 
php artisan passport:install // 安裝 passport 認證
php artisan migrate // 驅動內建的 App\User Eloquent 模型

好像寫過會員系統,但是除了這幾行指令,什麼都想不起來,面試怎麼辦?
寫技術筆記啦。

先輩姿勢 - HTTP & Session & CSRF

HTTP

在開始之前,先來快速複習一下 Http。

Http 是一種通訊協定,它有兩個基本特性:

  • 基於請求(Request)/回應(Response)模型
  • 無狀態(Stateless)通訊協定

換句話說,就是要有請求才有回應,每次回應完就會忘記你是誰。

Session

因為 HTTP 協定是無狀態這一個特點,有人想出一種方法叫做 session,就是把請求的狀態(已經登入過這件事)存起來,該怎麼做呢?就是接下來要討論的,方法不只一種。你可以把請求狀態,加密存在本地的某個地方,發請求的時候帶上去。或者,在本地只保存一個 SessionID,每次發請求的時候帶上再載入使用者狀態。

這邊舉例的方法是 PHP 的內建 _SESSION 函式。這種方法是上述第二種,在本地保存 SessionID,server 保存使用者狀態,比對後存取。

session_start(); // 啟動 session
$_SESSION["user_id"] = $user_id; // 儲存 session 內容
$_SESSION["user_ip"] = $user_ip;

session_start() 的功能是建立、發送跟載入 PHPSESID。

當使用者是第一次登入的時,瀏覽器沒有發送 PHPSESID 給 server。所以 session_start() 會在 server 建立 session 檔案,它長這樣 sess_{SESSIONID}。同時在 cookie 建立 PHPSESSID,內容是 SessionID。
當使用者是再次造訪,瀏覽器會自動帶上有 PHPSESID 的 cookie,session_start() 就會去 server 的資料夾裡尋找跟 cookie 裡 session ID 相同的檔案。

登入頁面

// 如果 session 是空的
if ( !isset($_SESSION["membername"]) && $_SESSION["membername"] == "" ) {
    // 比對 admin 帳號和密碼,正確
    if( $_POST["username"]=="admin" && $_POST["password"]=="0000" ){
        // session 記錄目前登入的人是 admin
        $_SESSION["membername"] = "admin";
    }
}

admin 登入判斷

if ( isset($_SESSION["membername"]) && $_SESSION["membername"] == "admin" ) {
    // 進入 admin 登入後畫面
} else {
    // 
}

web.php or api.php

還記得當初打開 routes 一看不得了有四個檔案,到底要把路由寫在哪個檔案咧?

預設路由檔案
routes 目錄中的路由檔案定義了所有的 Laravel 路由。這些檔案會自動被框架載入。routes/web.php 定義網頁介面的路由。這些路由被分配到 web 中介層群組,提供像是 session 狀態和 CSRF 保護的特性。routes/api.php 中的路由是無狀態的,且被分配到 api 中介層群組。
對大部分的應用程式來說,你會先由在 routes/web.php 檔案中定義路由開始。routes/web.php 中定義的路由可以透過在瀏覽器中輸入已定義的路由 URL 來訪問。例如,你可以在瀏覽器中瀏覽 http://your-app.dev/user 來訪問以下路由:

其實 5.3 之後官方文件,就有寫清楚 認證(Authentication)API 認證 的差別,web.php、api.php,都是給 HTTP 協定用的,但是 web.php 有預設用 session 機制、CSRF 保護。

CSRF 保護
任何指向 web 路由檔案中定義的 POST、PUT 或 DELETE 路由的 HTML 表單都應該包含一個 CSRF token 欄位。否則請求會被拒絕。

像是這樣:

<form method="POST" action="/profile">
    {{ csrf_field() }}
    ...
</form>

web 中介層群組的 VerifyCsrfToken 中介層,會自動驗證表單請求的 token 是否與儲存在 session 的 token 一致

認證 Authentication

簡單的講完 session 了,但我記得我們是想解釋 Passport 是什麼、它做了什麼。
所以要來講認證。

打開官方文件,嗯嗯,這裡都講過了,等等 Guard 又是什麼...

在 Laravel 的核心中,身份驗證工具是由「守衛」和「提供者」所組成。守衛定義了在每個請求中,如何與使用者進行身份驗證。舉例來說,Laravel 內建的一個 session 守衛會使用 session 儲存器和 cookies 來維護驗證狀態。然後另一個 token 守衛會使用每個請求所傳遞的「API token」來認證使用者。

好ㄅ,來看看 config/auth.php

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

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],

Illuminate\Contracts\Auth\Guard

Guard 是一個介面。
Web 與 Api 預設的 driver 來自於實作 Guard 的 Illuminate\Auth\SessionGuardIlluminate\Auth\TokenGuard

寫到這裡還沒講到 passport 但又快要截稿了,明天繼續...

參考資料

#Laravel #後端 #新手 #面試





一個新手的筆記。本系列文適合有多年程式開發經驗者,或具備思考與查證能力者閱讀。適合程式課程開發者參考,可以了解新手可憐的小腦袋;嚴禁寫作業照抄,一定不及格。

留言討論