Laravel 8 使用 JWT

tags: Web PHP Laravel API Auth
category: Back-End
description: Laravel 8 安裝與使用 JWT (json web token)
created_at: 2021/06/28 04:00:00

cover image

先開一個新的Laravel Project吧!

$ laravel new jwt-auth-app

事前準備

  • 設定好你的.env
  • 執行 php artisan migrate 產生 users 資料表

透過 Composer 安裝 jwt 套件

$ composer require tymon/jwt-auth

設定 config/app.php

    'providers' => [
        ...,
        Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
    ],

    'aliases' => [
        ...,
        'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
        'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ],

產生 config/jwt.php

$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

在 .env 產生 jwt secret key

$ php artisan jwt:secret

會在 .env 中看到類似以下的東西

JWT_SECRET=jwt_secret_key

設定你的 User Model

去實作JWTSubject介面,他在Tymon\JWTAuth\Contracts\JWTSubject,必須實現下面兩個方法

  • getJWTIdentifier()
  • getJWTCustomClaims()

example:

use Tymon\JWTAuth\Contracts\JWTSubject;


class User extends Authenticatable implements JWTSubject
{
    ...
        /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

設定 config/auth.php

    'defaults' => [
        'guard' => 'api',
        ...
    ],

    'guards' => [
        ...,
        'api' => [
            'driver' => 'jwt',
            ...
        ],
    ],

建立 Controller 測試

$ php artisan make:controller AuthController

填入以下程式碼,沒有做validation,只講求jwt運作正常

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $credentials = $request->only(['email', 'password']);

        if (!$token = auth()->attempt($credentials)) {
            return response()->json('Unauthorized.', 401);
        }

        return response()->json([
            'token' => $token,
            'expires_in' => auth()->factory()->getTTL() * 60
        ]);
    }

    public function logout()
    {
        auth()->logout();
        return response()->json();
    }

    public function userProfile()
    {
        return response()->json(auth()->user());
    }

    public function refreshToken()
    {
        $token = auth()->refresh();
        return response()->json([
            'token' => $token,
            'expires_in' => auth()->factory()->getTTL() * 60
        ]);
    }
}

註冊路由

use App\Http\Controllers\AuthController;


Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout']);
Route::post('/refresh', [AuthController::class, 'refreshToken']);
Route::get('/user-profile', [AuthController::class, 'userProfile']);

測試


建立 UserSeeder

$ php artisan make:seeder UserSeeder

他會存在 database/seeders資料夾中,然後填入以下內容

<?php

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        User::create([
            'name' => 'test',
            'email' => '[email protected]',
            'password' => Hash::make('1234')
        ]);
    }
}

在DatabaseSeeder.php中註冊

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UserSeeder::class
        ]);
    }
}

執行seeder

$ php artisan db:seed

執行伺服器

$ php artisan serv

打開你的 API 測試軟體

Endpoint: /login

傳入

{
    "email": "[email protected]",
    "password": "1234"
}

輸出

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODgwMFwvYXBpXC9sb2dpbiIsImlhdCI6MTYyNDg3NzIyOSwiZXhwIjoxNjI0ODgwODI5LCJuYmYiOjE2MjQ4NzcyMjksImp0aSI6IloySlNYMm5aMFFFcFdBZGQiLCJzdWIiOjEsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjcifQ.7EPqF9WCOdzNpoZar0oq6Vq9YjUZMvfKSEKxpf3fmy0",
    "expires_in": 3600
}

接下來在 header 帶入 Bearer Token,格式如下

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODgwMFwvYXBpXC9sb2dpbiIsImlhdCI6MTYyNDg3NzIyOSwiZXhwIjoxNjI0ODgwODI5LCJuYmYiOjE2MjQ4NzcyMjksImp0aSI6IloySlNYMm5aMFFFcFdBZGQiLCJzdWIiOjEsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjcifQ.7EPqF9WCOdzNpoZar0oq6Vq9YjUZMvfKSEKxpf3fmy0

Endpoing: /user-profile

{
    "id": 1,
    "name": "test",
    "email": "[email protected]",
    "email_verified_at": null,
    "created_at": "2021-06-28T10:44:02.000000Z",
    "updated_at": "2021-06-28T10:44:02.000000Z"
}

Endpoint: /refresh

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODgwMFwvYXBpXC9yZWZyZXNoIiwiaWF0IjoxNjI0ODc3NDg1LCJleHAiOjE2MjQ4ODExNDMsIm5iZiI6MTYyNDg3NzU0MywianRpIjoidE5lZGs2ZVoxUzRUb09NQyIsInN1YiI6MSwicHJ2IjoiMjNiZDVjODk0OWY2MDBhZGIzOWU3MDFjNDAwODcyZGI3YTU5NzZmNyJ9.vsOMcdKNbO8WUAPYi7F1JoeQ0mgIUUVVsY1qHsPIlbY",
    "expires_in": 3600
}

再來需要使用新的token,舊的已經不可用

Endpoint: /logout

[]

登出完成!




最後更新時間: 2021年06月28日.