在Laravel 6 REST API中應用JSON Web Token (JWT)

Yu-Cheng Hung
10 min readJan 2, 2020

--

2020新年快樂!筆者最近對於Laravel 6架構又有了比較深的了解,特別是有關Laravel 6內建預設使用者登入認證方式(SESSION、COOKIE)的部分,查詢資料的過程中發現了JWT這個有別於傳統Token的認證型態,因此去玩了一下如何在Laravel 6的REST API中應用JWT並將過程記錄下來分享給各位。

什麼是JWT?

JWT全名為JSON Web Token,是一種JSON格式的新形態Web Token, 常用來作使用者驗證與傳輸資料,比起傳統Token具有下列優點:

● 極具狀態性,安全性高, 解決了跨網域請求偽造攻擊 (CSRF Attack)。

● 本身是個JSON格式的輕量級規範, 可以經由URL parameter、POST parameter或者header傳輸,傳輸速度快。

● 能夠直接在 JWT (PAYLOAD)中存放使用者資訊,而不用額外呼叫資料庫。

JWT為一組字串,分為三個部分並由 . 串接而成:

[HEADER].[PAYLOAD].[SIGNATURE]

官網範例

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

有關三個部份的功用及說明請參考下列連結文章:

簡潔安全的資料傳輸方式 — JSON Web Token(JWT)

接下來就讓我們開始實作吧!

程式碼準備

創建一個Laravel 6專案:

$ composer create-project laravel/laravel JWTApp

下載JWT package:

$ composer require tymon/jwt-auth:dev-develop

執行package publish:

$ php artisan vendor:publish

選擇 Provider: Tymon\JWTAuth\Providers\LaravelServiceProvider

成功後會在config中產生一個jwt.php檔案。

接著我們必須要替JWT authentication token產生一組加密的金鑰:

$ php artisan jwt:secret

執行成功:

而JWT package本身預設有一個middleware,可用於我們API routes中,將以下程式碼輸入app/Http/Kernel.php$routeMiddleware中:

'auth.jwt'  =>  \Tymon\JWTAuth\Http\Middleware\Authenticate::class,

接著至routes/api.php設定下列routes:

Route::post('login', 'ApiController@login');
Route::post('register', 'ApiController@register');

Route::group(['middleware' => 'auth.jwt'], function () {
Route::get('logout', 'ApiController@logout');

Route::get('tasks', 'TaskController@index');
Route::get('tasks/{id}', 'TaskController@show');
Route::post('tasks', 'TaskController@store');
Route::put('tasks/{id}', 'TaskController@update');
Route::delete('tasks/{id}', 'TaskController@destroy');
});

設定好routes後,將app/User.phpModel加入JWT的getJWTIdentifiergetJWTCustomClaimsfunction並更新程式碼:

現在我們開始來設定API所需要的各項功能,首先是註冊功能,需創建一個新的form request class:

$ php artisan make:request RegistrationFormRequest

成功後在app/Http/Requests產生一個RegistrationFormRequest.php檔案,並更新成下列程式碼,規定新使用者註冊需輸入nameemailpassword

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegistrationFormRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/

public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/

public function rules()
{
return [
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:6|max:10'
];
}
}

然後新創一個APIControllerController:

$ php artisan make:controller APIController

成功後至app/Http/Controllers更改APIController.php程式碼如下,加入loginlogoutregister三個function:

目前我們已經完成了使用者驗證的部分,接著要對CRUD的各項操作和資料庫進行創建,使用下列指令一次創建 Model、Migration、Controller:

$ php artisan make:model Task -mc

完成後至database/migrations設定資料庫資料:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTasksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/

public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->string('title');
$table->text('description')->nullable();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');

$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/

public function down()
{
Schema::dropIfExists('tasks');
}
}

設定好後執行:

$ php artisan migrate

下一步至app/更新Task.php程式碼:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
/**
* @var string
*/

protected $table = 'tasks';

/**
* @var array
*/

protected $guarded = [];
}

回去app/User.php並加入下列function,一個使用者(user)對應多個活動(tasks):

/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/

public function tasks()
{
return $this->hasMany(Task::class);
}

接著來完成app/Http/Controllers/TaskController.php中的CRUD:

至此所有該做的程式碼創建與設定皆已完成,那我們就趕緊來測試看看吧!

REST API測試

開啟測試server( localhost:8000):

$ php artisan serve

之後的各項測試皆使用Postman,讀者可參考官網資訊。

註冊一個新用戶

輸入註冊資訊並發送,若成功則傳回綠框資訊!

以剛註冊好的使用者進行登入

為經過身分驗證的使用者創建一個新的活動紀錄

輸入titledescription和使用者登入token,成功後同樣回傳綠框資訊。

由JWT token來獲得夾帶於其中的資訊

成功時即可獲得JWT token中帶有的相關資訊!

經過這一系列的操作,相信大家對於JWT都有了基本的概念,那就下次見啦!掰掰!

2020/10/27更新:

目前我已將這個練習的程式碼上傳至Github,有興趣的讀者可以參考看看,有任何問題歡迎與我交流討論,謝謝大家!

我的email:rommelhong@gmail.com

Github:https://github.com/rommelhong/jwt-laravel6

--

--