首頁  >  文章  >  php框架  >  使用Laravel整合JWT認證開發RestfulApi

使用Laravel整合JWT認證開發RestfulApi

Guanhui
Guanhui轉載
2020-05-09 10:43:452354瀏覽

在這篇文章中,我們將學習如何使用 JWT 驗證在 Laravel 中建立 restful API 。 JWT 代表 JSON Web Tokens 。我們還將使用 API 為用戶產品建立功能齊全的 CRUD 應用。

在使用跨平台應用程式時, API 是一個非常不錯的選擇。除了網站,您的產品可能還有 Android 和 iOS 應用程式。在這種情況下, API 也是同樣出色的,因為您可以在不更改任何後端程式碼的情況下編寫不同的前端。使用 API 時,只需使用一些參數點擊 GET , POST 或其他類型的請求,伺服器就會返回 JSON (JavaScript Object Notation) 格式的一些數據,這些數據由客戶端應用程式處理。

說明

我們先寫下我們的應用程式詳細資訊和功能。我們將使用 JWT 驗證在 laravel 中使用 restful API 建立基本使用者產品清單。

A User 將會使用以下功能

  • 註冊並建立一個新帳戶

  • 登錄到他們的帳戶

  • 註銷和丟棄token 並離開應用程式

  • 以取得登入使用者的詳細資訊

  • ##檢索可供使用者使用的產品清單

  • 按ID 尋找特定產品

  • 將新產品新增至使用者產品清單中

  • 編輯現有產品詳細資料

  • 從使用者清單中刪除現有產品

A

User 必填

  • name

  • #email

  • password

A

Product 必填

  • name

  • price

  • quantity

#建立新的專案

透過執行下面的命令,我們就可以開始並建立新的Laravel 專案。

composer create-project --prefer-dist laravel/laravel jwt

這會在名為 jwt 的目錄下建立一個新的 Laravel 專案。

設定 JWT 擴充包

我們會使用 tymondesigns/jwt-auth 擴充包來讓我們在 Laravel 中使用 JWT。

安裝 tymon/jwt-auth 擴充包

讓我們在這個 Laravel 應用程式中安裝這個擴充包。如果您正在使用Laravel 5.5 或以上版本,請執行以下指令來取得dev-develop 版本的JWT 套件:

composer require tymon/jwt-auth:dev-develop --prefer-source

如果您正在使用Laravel 5.4 或以下版本,那麼請執行下面這條指令:

composer require tymon/jwt-auth

對於Laravel 版本低於5.5 的應用,您也要在config/app.php 檔案中設定服務提供者和別名。

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

如果您的 Laravel 版本為 5.5 或以上,Laravel 會進行「套件自動發現」。

發布設定檔

對於5.5 或以上版本的Laravel,請使用下方這條指令來發佈設定檔:

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

對於先前先前版本的Laravel,那麼應該執行下面這條指令:

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

上面的指令會產生config/jwt.php 設定檔。除去註解部分,設定檔會像這樣:

<?php
return [
    &#39;secret&#39; => env(&#39;JWT_SECRET&#39;),
    &#39;keys&#39; => [
        &#39;public&#39; => env(&#39;JWT_PUBLIC_KEY&#39;),
        &#39;private&#39; => env(&#39;JWT_PRIVATE_KEY&#39;),
        &#39;passphrase&#39; => env(&#39;JWT_PASSPHRASE&#39;),
    ],
    &#39;ttl&#39; => env(&#39;JWT_TTL&#39;, 60),
    &#39;refresh_ttl&#39; => env(&#39;JWT_REFRESH_TTL&#39;, 20160),
    &#39;algo&#39; => env(&#39;JWT_ALGO&#39;, &#39;HS256&#39;),
    &#39;required_claims&#39; => [
        &#39;iss&#39;,
        &#39;iat&#39;,
        &#39;exp&#39;,
        &#39;nbf&#39;,
        &#39;sub&#39;,
        &#39;jti&#39;,
    ],
    &#39;persistent_claims&#39; => [
        // &#39;foo&#39;,
        // &#39;bar&#39;,
    ],
    &#39;lock_subject&#39; => true,
    &#39;leeway&#39; => env(&#39;JWT_LEEWAY&#39;, 0),
    &#39;blacklist_enabled&#39; => env(&#39;JWT_BLACKLIST_ENABLED&#39;, true),
    &#39;blacklist_grace_period&#39; => env(&#39;JWT_BLACKLIST_GRACE_PERIOD&#39;, 0),
    &#39;decrypt_cookies&#39; => false,
    &#39;providers&#39; => [
        &#39;jwt&#39; => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,
        &#39;auth&#39; => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
        &#39;storage&#39; => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
    ],
];

產生JWT 金鑰##JWT 令牌透過一個加密的金鑰來簽發。對於 Laravel 5.5 或以上版本,執行下面的命令來產生密鑰以便用於簽發令牌。

php artisan jwt:secret

Laravel 版本低於 5.5 的則運行:

php artisan jwt:generate

這篇教學使用 Laravel 5.6。教程中接下來的步驟只在 5.5 和 5.6 測試過。可能不適用於 Laravel 5.4 或以下版本。您可以閱讀 針對舊版 Laravel 的文件。

註冊中間件JWT 認證擴充包附帶了允許我們使用的中間件。在 app/Http/Kernel.php 中註冊 auth.jwt 中間件:

protected $routeMiddleware = [
    ....
    &#39;auth.jwt&#39; => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];

這個中間件會透過檢查請求中附帶的令牌來校驗使用者的認證。如果使用者未認證,這個中間件會拋出 UnauthorizedHttpException 例外。

設定路由開始之前,我們將為所有本教學討論的點設定路由。打開 routes/api.php 並將下面的路由複製到您的檔案中。

Route::post(&#39;login&#39;, &#39;ApiController@login&#39;);
Route::post(&#39;register&#39;, &#39;ApiController@register&#39;);
Route::group([&#39;middleware&#39; => &#39;auth.jwt&#39;], function () {
    Route::get(&#39;logout&#39;, &#39;ApiController@logout&#39;);
    Route::get(&#39;user&#39;, &#39;ApiController@getAuthUser&#39;);
    Route::get(&#39;products&#39;, &#39;ProductController@index&#39;);
    Route::get(&#39;products/{id}&#39;, &#39;ProductController@show&#39;);
    Route::post(&#39;products&#39;, &#39;ProductController@store&#39;);
    Route::put(&#39;products/{id}&#39;, &#39;ProductController@update&#39;);
    Route::delete(&#39;products/{id}&#39;, &#39;ProductController@destroy&#39;);
});

更新 User 模型#JWT 需要在 User 模型中實作 Tymon\JWTAuth\Contracts\JWTSubject 介面。此介面需要實作兩個方法  getJWTIdentifier 和 getJWTCustomClaims。使用以下內容更新 app/User.php 。

<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
    use Notifiable;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        &#39;name&#39;, &#39;email&#39;, &#39;password&#39;,
    ];
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        &#39;password&#39;, &#39;remember_token&#39;,
    ];
    /**
     * 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 [];
    }
}

JWT 驗證邏輯#讓我們使用 JWT 驗證在 laravel 中寫 Restful API 的邏輯。

用户注册时需要姓名,邮箱和密码。那么,让我们创建一个表单请求来验证数据。通过运行以下命令创建名为 RegisterAuthRequest 的表单请求:

php artisan make:request RegisterAuthRequest

它将在 app/Http/Requests 目录下创建 RegisterAuthRequest.php 文件。将下面的代码黏贴至该文件中。

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegisterAuthRequest extends FormRequest
{
    /**
     * 确定是否授权用户发出此请求
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }
    /**
     * 获取应用于请求的验证规则
     *
     * @return array
     */
    public function rules()
    {
        return [
            &#39;name&#39; => &#39;required|string&#39;,
            &#39;email&#39; => &#39;required|email|unique:users&#39;,
            &#39;password&#39; => &#39;required|string|min:6|max:10&#39;
        ];
    }
}

运行以下命令创建一个新的 ApiController :

php artisan make:controller ApiController

这将会在 app/Http/Controllers 目录下创建 ApiController.php 文件。将下面的代码黏贴至该文件中。

<?php
namespace App\Http\Controllers;
use App\Http\Requests\RegisterAuthRequest;
use App\User;
use Illuminate\Http\Request;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class ApiController extends Controller
{
    public $loginAfterSignUp = true;
    public function register(RegisterAuthRequest $request)
    {
        $user = new User();
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();
        if ($this->loginAfterSignUp) {
            return $this->login($request);
        }
        return response()->json([
            &#39;success&#39; => true,
            &#39;data&#39; => $user
        ], 200);
    }
    public function login(Request $request)
    {
        $input = $request->only(&#39;email&#39;, &#39;password&#39;);
        $jwt_token = null;
        if (!$jwt_token = JWTAuth::attempt($input)) {
            return response()->json([
                &#39;success&#39; => false,
                &#39;message&#39; => &#39;Invalid Email or Password&#39;,
            ], 401);
        }
        return response()->json([
            &#39;success&#39; => true,
            &#39;token&#39; => $jwt_token,
        ]);
    }
    public function logout(Request $request)
    {
        $this->validate($request, [
            &#39;token&#39; => &#39;required&#39;
        ]);
        try {
            JWTAuth::invalidate($request->token);
            return response()->json([
                &#39;success&#39; => true,
                &#39;message&#39; => &#39;User logged out successfully&#39;
            ]);
        } catch (JWTException $exception) {
            return response()->json([
                &#39;success&#39; => false,
                &#39;message&#39; => &#39;Sorry, the user cannot be logged out&#39;
            ], 500);
        }
    }
    public function getAuthUser(Request $request)
    {
        $this->validate($request, [
            &#39;token&#39; => &#39;required&#39;
        ]);
        $user = JWTAuth::authenticate($request->token);
        return response()->json([&#39;user&#39; => $user]);
    }
}

让我解释下上面的代码发生了什么。

在 register 方法中,我们接收了 RegisterAuthRequest 。使用请求中的数据创建用户。如果 loginAfterSignUp 属性为 true ,则注册后通过调用 login 方法为用户登录。否则,成功的响应则将伴随用户数据一起返回。

在 login 方法中,我们得到了请求的子集,其中只包含电子邮件和密码。以输入的值作为参数调用  JWTAuth::attempt() ,响应保存在一个变量中。如果从 attempt 方法中返回 false ,则返回一个失败响应。否则,将返回一个成功的响应。

在 logout 方法中,验证请求是否包含令牌验证。通过调用 invalidate 方法使令牌无效,并返回一个成功的响应。如果捕获到 JWTException 异常,则返回一个失败的响应。

在 getAuthUser 方法中,验证请求是否包含令牌字段。然后调用 authenticate 方法,该方法返回经过身份验证的用户。最后,返回带有用户的响应。

身份验证部分现在已经完成。

构建产品部分

要创建产品部分,我们需要 Product 模型,控制器和迁移文件。运行以下命令来创建 Product 模型,控制器和迁移文件。

php artisan make:model Product -mc

它会在 database/migrations 目录下创建一个新的数据库迁移文件 create_products_table.php,更改 up 方法。

public function up()
{
    Schema::create(&#39;products&#39;, function (Blueprint $table) {
        $table->increments(&#39;id&#39;);
        $table->integer(&#39;user_id&#39;);
        $table->string(&#39;name&#39;);
        $table->integer(&#39;price&#39;);
        $table->integer(&#39;quantity&#39;);
        $table->timestamps();
        $table->foreign(&#39;user_id&#39;)
            ->references(&#39;id&#39;)
            ->on(&#39;users&#39;)
            ->onDelete(&#39;cascade&#39;);
    });
}

向 Product 模型中添加 fillable 属性。在 app 目录下打开 Product.php 文件并添加属性。

protected $fillable = [
    &#39;name&#39;, &#39;price&#39;, &#39;quantity&#39;
];

现在在 .env 文件中设置数据库凭证,并通过运行以下命令迁移数据库。

php artisan migrate

现在,我们必须在 User 模型中添加一个关系来检索相关产品。在 app/User.php 中添加以下方法。

public function products()
{
    return $this->hasMany(Product::class);
}

在 app/Http/Controllers 目录下打开 ProductController.php 文件。在文件开头添加 use 指令覆盖上一个。

use App\Product;
use Illuminate\Http\Request;
use JWTAuth;

现在我们将实现五个方法。

index, 为经过身份认证的用户获取所有产品列表

show, 根据 ID 获取特定的产品

store, 将新产品存储到产品列表中

update, 根据 ID 更新产品详情

destroy, 根据 ID 从列表中删除产品

添加一个构造函数来获取经过身份认证的用户,并将其保存在 user 属性中。

protected $user;
public function __construct()
{
    $this->user = JWTAuth::parseToken()->authenticate();
}

parseToken 将解析来自请求的令牌, authenticate 通过令牌对用户进行身份验证。

让我们添加 index 方法。

public function index()
{
    return $this->user
        ->products()
        ->get([&#39;name&#39;, &#39;price&#39;, &#39;quantity&#39;])
        ->toArray();
}

上面的代码非常简单,我们只是使用 Eloquent 的方法获取所有的产品,然后将结果组成一个数组。最后,我们返回这个数组。Laravel 将自动将其转换为 JSON ,并创建一个为 200 成功的响应码。

继续实现 show 方法。

public function show($id)
{
    $product = $this->user->products()->find($id);
    if (!$product) {
        return response()->json([
            &#39;success&#39; => false,
            &#39;message&#39; => &#39;Sorry, product with id &#39; . $id . &#39; cannot be found&#39;
        ], 400);
    }
    return $product;
}

这个也非常容易理解。我们只需要根据 ID 找到该产品。如果产品不存在,则返回 400 故障响应。否则,将返回产品数组。

接下来是 store 方法

public function store(Request $request)
{
    $this->validate($request, [
        &#39;name&#39; => &#39;required&#39;,
        &#39;price&#39; => &#39;required|integer&#39;,
        &#39;quantity&#39; => &#39;required|integer&#39;
    ]);
    $product = new Product();
    $product->name = $request->name;
    $product->price = $request->price;
    $product->quantity = $request->quantity;
    if ($this->user->products()->save($product))
        return response()->json([
            &#39;success&#39; => true,
            &#39;product&#39; => $product
        ]);
    else
        return response()->json([
            &#39;success&#39; => false,
            &#39;message&#39; => &#39;Sorry, product could not be added&#39;
        ], 500);
}

在 store 方法中,验证请求中是否包含名称,价格和数量。然后,使用请求中的数据去创建一个新的产品模型。如果,产品成功的写入数据库,会返回成功响应,否则返回自定义的 500 失败响应。

实现 update 方法

public function update(Request $request, $id)
{
    $product = $this->user->products()->find($id);
    if (!$product) {
        return response()->json([
            &#39;success&#39; => false,
            &#39;message&#39; => &#39;Sorry, product with id &#39; . $id . &#39; cannot be found&#39;
        ], 400);
    }
    $updated = $product->fill($request->all())
        ->save();
    if ($updated) {
        return response()->json([
            &#39;success&#39; => true
        ]);
    } else {
        return response()->json([
            &#39;success&#39; => false,
            &#39;message&#39; => &#39;Sorry, product could not be updated&#39;
        ], 500);
    }
}

在 update 方法中,我们通过 id 取得产品。如果产品不存在,返回一个 400 响应。然后,我们把请求中的数据使用 fill 方法填充到产品详情。更新产品模型并保存到数据库,如果记录成功更新,返回一个 200 成功响应,否则返回 500 内部服务器错误响应给客户端。

现在,让我们实现 destroy 方法。

public function destroy($id)
{
    $product = $this->user->products()->find($id);
    if (!$product) {
        return response()->json([
            &#39;success&#39; => false,
            &#39;message&#39; => &#39;Sorry, product with id &#39; . $id . &#39; cannot be found&#39;
        ], 400);
    }
    if ($product->delete()) {
        return response()->json([
            &#39;success&#39; => true
        ]);
    } else {
        return response()->json([
            &#39;success&#39; => false,
            &#39;message&#39; => &#39;Product could not be deleted&#39;
        ], 500);
    }
}

在 destroy 方法中,我们根据 ID 获取产品,如果产品不存在,则返回 400 响应。然后我们删除产品后并根据删除操作的成功状态返回适当的响应。

控制器代码现在已经完成,完整的控制器代码在这。

测试

我们首先来测试身份认证。我们将使用 serve 命令在开发机上启动 Web 服务,你也可以使用虚拟主机代替。运行以下命令启动 Web 服务。

php artisan serve

它将监听 localhost:8000

为了测试 restful API's,我们使用 Postman。填写好请求体之后,我们请求一下 register 路由。

使用Laravel整合JWT認證開發RestfulApi

發送請求,你將獲得令牌。

使用Laravel整合JWT認證開發RestfulApi

我們的用戶現在已註冊並通過身份驗證。我們可以發送另一個請求來偵測 login 路由,結果會傳回 200 和令牌。

使用Laravel整合JWT認證開發RestfulApi

取得使用者詳情

使用Laravel整合JWT認證開發RestfulApi

#測試認證已完成。接下來測試產品部分,先建立一個產品。

使用Laravel整合JWT認證開發RestfulApi

現在,透過請求 index 方法取得產品。

使用Laravel整合JWT認證開發RestfulApi

你可以測試其它路由,它們都會正常運作。

推薦教學:《Laravel教學

以上是使用Laravel整合JWT認證開發RestfulApi的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:learnku.com。如有侵權,請聯絡admin@php.cn刪除