使用 Laravel Sanctum 輕鬆驗證 Vue SPA

image

Laravel Sanctum (之前稱爲 Laravel Airlock), 於今年早些時候發佈,是一個輕量級的擴展包,可使得在單頁面應用或者本地移動應用上構建身份驗證的流程變得儘量地簡單和輕鬆。在此以前,你要麼使用基於 sessionsWeb 中間件 ,要麼使用外部集成的依賴包,如 Tymonjwt-auth, 然而如今,你可使用 Sanctum 來完成有狀態的身份驗證和基於 token 身份驗證。php

在這個簡短的測試中,我會向你展現如何讓運用 Laravel Sanctum 從 0 開始構建一個項目。 咱們將建立一個虛擬 API,經過 Vue 組件對用戶進行身份驗證,並獲取與該登陸用戶相關聯的數據。前端

準備就緒,接下來,讓咱們一塊兒盤它!vue

建立測試 API

咱們須要作的第一件事是建立一個能夠從中獲取數據的 API 接口。我構思了一個超級簡單的應用,用於檢索展現每一個用戶的祕密列表。ios

我已經安裝了一個開箱即用的 Laravel 應用程序,而且將其跟 MySQL 數據庫一塊兒配置運行在我使用 Laravel Docker setup 搭建的本地環境中。我要作的第一件事就是去爲咱們的 secret 建立一個模型類以及相關的遷移文件 ,這裏咱們能夠很輕鬆地使用 artisan , 經過命令行來完成這些操做。laravel

php artisan make:model Secret --migration

接下來,讓咱們打開遷移文件,而且添加一些足以描述一個 secret 須要的數據列。 我認爲咱們須要的 (除了 Laravel 提供的默認 ID 和時間戳) 是一個用於跟用戶關聯的 user_id 整數字段 ,以及一個用於實實在在地保存用戶 secret 信息的字段。web

Schema::create('secrets', function (Blueprint $table) {
    $table->id();
    $table->integer('user_id');
    $table->text('secret');
    $table->timestamps();
});

而後,接着運行數據庫遷移命令生成 users 和 secrets 兩個表。面試

php artisan migrate

咱們須要對應用程序的兩個模型類進行一些簡單的修改,用於啓用兩個模型類之間的關聯關係,因此接下來讓咱們打開這兩個模型類文件,而且開始修改 :sql

// User.php

public function secrets()
{
    return $this->hasMany('App\Secret');
}
// Secret.php

public function user()
{
    return $this->belongsTo('App\User');
}

咱們 API 結構的最後一部分就是實際的路由和控制器。咱們將僅僅訪問一條網頁路徑就能夠展現出跟當前用戶的全部 secrets 信息。因此,我在 routes/api.php 文件中添加了如下內容:shell

Route::get('/secrets', 'SecretController@index');

可使用 Artisan 命令輕鬆建立此控制器:數據庫

php artisan make:controller SecretController

打開剛剛建立的控制器,讓咱們建立 index 方法,先返回全部的密鑰。由於 如今 咱們還沒法得到通過身份驗證的用戶:

public function index()
{
    return App\Secret::all();
}

咱們的虛擬 API 如今已經完成,來建立一些假用戶和密鑰吧。

填充數據庫

你能夠輕鬆地直接進入數據庫並手動填充用戶,建立控制器和表單以供用戶輸入本身的數據,或者使用 Artisan tinker 來半自動建立用戶。我將跳過這些方法,使用內置的 Laravel 工廠爲咱們的用戶和密鑰生成假數據。

Laravel 帶有一個開箱即用的 UserFactory.php 類,用來生成假用戶。咱們將爲密鑰建立一個相似的工廠類。在終端中運行如下 Artisan 命令:

php artisan make:factory SecretFactory --model=Secret

打開生成的文件,咱們只需用 user_id 和 secret 這兩個數據填充每一個模型:

$factory->define(Secret::class, function (Faker $faker) {
    return [
        'user_id' => 1,
        'secret' => $faker->text
    ];
});

你可能想知道爲何咱們要在上面的片斷中的 user_id 中使用硬編碼。由於我不想基於用戶數量隨機生成它,而是但願對其進行更多控制。稍後,我將告訴你當咱們開始生成祕密時如何覆蓋它。

讓咱們從建立幾個假用戶開始。經過從站點根目錄運行 php artisan tinker 命令來打開 Tinker Shell. 打開後,咱們能夠經過兩次運行 global factory helper 來建立兩個用戶:

factory(App\User::class)->create(); // 與make不一樣,create 將咱們的用戶保存在數據庫中

Now that we have them generated, let’s create our secrets. I’m going to run the following in the tinker shell twice to create two for user_id 1:
如今咱們已經生成了它們,讓咱們建立咱們的密鑰。我在 tinker 中運行如下命令兩次,爲 user_id 1 建立兩個密鑰:

factory(App\Secret::class)->create();

可是若是第二個密鑰擁有不一樣 ID 的用戶呢?覆蓋工廠類中的任何值都很容易,咱們要作的就是將覆蓋數組傳遞給 create() 方法。所以,咱們將運行兩次如下命令,爲第二個假用戶建立兩個密鑰:

factory(App\Secret::class)->create(['user_id' => 2]);

咱們的數據庫中填充了足夠的假數據以後,讓咱們繼續安裝和準備 Laravel Sanctum 軟件包。

安裝 Laravel Sanctum

安裝垂手可得,能夠經過在終端中運行一些命令來完成。首先,讓咱們使用 Composer 安裝該軟件包:

composer require laravel/sanctum

接下來運行如下命令發佈遷移文件(並運行遷移):

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

Sanctum 安裝的最後一部分要求咱們修改 app\Http\Kernel.php 文件以包含一箇中間件,該中間件會將 Laravel 的會話 cookie 注入到咱們的應用程序前端中。這最終將使咱們可以以通過身份驗證的用戶身份傳遞和檢索數據:

'api' => [
    EnsureFrontendRequestsAreStateful::class,
    'throttle:60,1'
]

如今,咱們能夠進入應用程序的前端了!

構建前端

從 Laravel 7 開始,前端和身份驗證模板已從主程序包中剝離,能夠單獨安裝。爲了進行演示,咱們將使用它和 Vue 來構建前端。

在應用程序的根目錄運行如下命令將幫助咱們配置環境:

composer require laravel/ui
php artisan ui vue --auth
npm install && npm run dev

上面的命令作了三件事:

  1. 使用 Composer 安裝 Laravel UI 軟件包
  2. 生成 JS/UI 文件、身份驗證模板和 package.json 修改
  3. 安裝前端依賴項並編譯開發環境的 JS/CSS 文件

我會把 welcome.blade.php 文件裏的全部內容拷貝到 app.blade.php 文件裏,而後把外部 div 裏的內容刪掉並添加一個 id=「app」 屬性。這將是咱們 Vue 應用程序的掛載點,如剛纔生成的 app.js 文件中所述。

讓咱們建立 Vue 組件,該組件將保存咱們的登陸表單並顯示一些 secret.

建立 Vue 組件

在此以前,咱們能夠經過命令: php artisan ui vue 來生快速成咱們的前端代碼,它默認會生成一個 resources/js/components/ExampleComponent.vue 組件事例。好了,如今讓咱們建立新的組件:SecretComponent.vue,它的代碼以下:

<template>

</template>
<script>
export default {
    data() {
        return {
            secrets: [],
            formData: {
                email: '',
                password: ''
            }
        }
    }
}
</script>

這裏有兩個字段返回,其中 secrets 字段是個數組,還有一個用戶存儲 email 和 password 字段的 formData 對象。

下面,咱們將在 template 標籤內構件咱們的登陸表單。

<template>
    <div>
        <div v-if="!secrets.length" class="row">
            <form action="#" @submit.prevent="handleLogin">
                <div class="form-row">
                    <input type="email" v-model="formData.email">
                </div>
                <div class="form-row">
                    <input type="password" v-model="formData.password">
                </div>
                <div class="form-row">
                    <button type="submit">Sign In</button>
                </div>
            </form>
        </div>
    </div>
</template>

好了,一個登陸表單建立完成,它可能看起來像下面這樣:

image

在上面代碼中,咱們禁用了 form 表單的默認提交操做,並將它移交給 Vue 的 Submit 來處裏。如今咱們建立 handleLogin 方法來處理用戶的登陸請求:

<script>
export default {
    data() {
        return {
            secrets: [],
            formData: {
                email: '',
                password: ''
            }
        }
    },
    methods: {
        handleLogin() {
            // 處理登陸請求
        }
    }
}
</script>

最後,不要忘記將咱們的組件註冊到 resources/js/app.js 文件中:

Vue.component('secret-component', require('./components/SecretComponent.vue).default);

而後在 app.blade.php 中使用該組件。如今咱們能夠經過 handleLogin() 方法驗證用戶登陸操做了。

用戶驗證

若是看過 Laravel Sanctum documentation 這篇文章,你應該知道 SPA 單頁應用的 csrf 保護實現方式,你須要先請求 /sanctum/csrf-cookie 以獲取 csrf token。

而後,咱們請求 /login 路由,並將咱們的 email 和 password 字段傳遞給後端接口處理。

如今讓咱們在 handleLogin() 方法中實現上面的需求:

handleLogin() {
    axios.get('/sanctum/csrf-cookie').then(response => {
        axios.post('/login', this.formData).then(response => {
            console.log('登陸成功!');
        }).catch(error => console.log(error)); // 若是驗證不匹配
    });
}

如今,使用當咱們輸入相應的信息你會發現流程已經走通。每一個請求都會受到 csrf 保護,併發送登陸接口所須要的 email 與 password 字段,即便如今沒有響應數據,個人程序依然會經過 Promise 繼續執行,而不會崩潰。

接下來要作什麼?讓咱們完成登陸操做吧!

用戶檢索

在咱們的 Vue 組件中,繼續建立名爲 getSecrets() 方法,該方法是用戶登錄成功以後,獲取用戶 secrets ,一般咱們會獲得一個 secrets 數組,以後咱們將咱們的獲得的新的數組替換組件中原有的數組。

打當用戶登陸成功以後,咱們調用 getSecrets() 函數以完成後續操做。

handleLogin() {
    axios.get('/sanctum/csrf-cookie').then(response => {
        axios.post('/login', this.formData).then(response => {
            this.getSecrets();
        }).catch(error => console.log(error)); // credentials didn't match
    });
},
getSecrets() {
    axios.get('/api/secrets').then(response => this.secrets = response.data);
}

可是,如今程序中咱們返回的是全部用戶 secrets。因此咱們須要在 index() 方修改它,以獲得正確的數據:

public function index(Request $request)
{
    return $request->user()->secrets;
}

在登陸成功以後,全部須要用戶驗證的接口中的請求頭中都會包含 laravel_session cookie,這樣 Sanctum 能夠經過該 cookie 來肯定並關聯當前請求的用戶。

以後,既可使用 $request 對象來獲取用戶的所有信息了,而後咱們將 secret 信息與用戶關聯,並將數據返回。

最後咱們將數據格式化、脫敏以後呈現給用戶:

<template>
    <div>
        <div v-if="secrets.length" class="row">
            <div class="secret" v-for="(secret, index) in secrets" :key="index">
                <strong v-text="secret.secret"></strong> - created at <span v-text="secret.created_at"></span>
            </div>
        </div>
    </div>
</template>

? 如今咱們刷新應用,並使用咱們 fake 的用戶數據登陸,就能夠看到如下頁面了:

image

至此,一個 SPA 單頁應用的登陸操做完成。

總結和後續

我僅僅剛開始接觸並使用該擴展,若是使用以上方式驗證用戶,則以後全部須要用戶信息的接口能夠實現像傳統 web 應用的登陸操做同樣,每一個請求都會攜帶用戶狀態。

固然,你也能夠用 token 令牌的方式實現 SPA 單頁應用的身份驗證,移動以及桌面應用。俗話說的好條條大路通羅馬。該文章只是圍繞 documentation 該擴展展開的討論與實踐。

更多學習內容能夠訪問【對標大廠】精品PHP架構師教程目錄大全,只要你能看完保證薪資上升一個臺階(持續更新)

以上內容但願幫助到你們,不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要的能夠點擊這裏進階PHP月薪30k>>>架構師成長路線【視頻、面試文檔免費獲取】

相關文章
相關標籤/搜索