本文承接前文 [Day 27] Call API use JWT in Laravel: 簡介 和 安裝 ,將自制一個 Member model,應用 tymon/jwt-auth 做出 Login/ Logout 功能和應用 attempt() 時,需注意事項。設定上會與 jwt-auth 的 Quick start 稍有不同:
Member model (implements JWTSubject, add getJWTIdentifier(), getJWTCustomClaims())<?php
namespace App\Models;
use Laravel\Sanctum\HasApiTokens;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Member extends Authenticatable implements JWTSubject
// class Member extends Authenticatable 
{
    use HasFactory, HasApiTokens, Notifiable;
    protected $fillable = [
        'name',
        'email',
        'password',
        'mobile',
    ];
    protected $hidden = [
        'password',
        'remember_token',
    ];
    /**
     * 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)
config/auth.php 初始設定 'defaults' 設置 'guard' => 'web' ,这意味著預設的身份驗證 guard 是 Web guard,通常用於傳統的 Web 應用程序,而不是 API。routes/api.php 設定的 Route 需加上 middlewaremiddleware('auth:api')->get('register' ..略),確保只有通過 API 身份驗證的用户才能訪問 /register
routes/api.php 的 Route:: 無需加上middleware('auth:api')
Route:: 寫作:<?php
Route::middleware('auth:member')->apiResource('products', ProductController::class)->only('index', 'show');
auth.php 可以設定多個 guard 在 'guards' 內,現下 Call Api ,Route:: 走 middleware('auth:member'),本例  auth.php 設定:
<?php
return [
    
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'members',
    ],
    'guards' => [
        'member' => [
            'driver' => 'jwt', 
            'provider' => 'members', // members table
        ], 
        
    ],
    'providers' => [
        'members' => [
            'driver' => 'eloquent',
            'model' => App\Models\Member::class,
        ],
    ],
    // ..略
];
php artisan make:controller AuthController
use Illuminate\Support\Facades\Auth;
Auth::) 來存取 Laravel 的認證服務attempt(),這個 attempt() 方法通常會用來處理來自網站「登入」表單的驗證Auth::attempt($credential)),則應該產生使用者的 token
Auth::attempt($credential) 為 true)後,可透過 Auth::user() 取得使用者資訊Auth::attempt($credential) 為 false),可能的原因是註冊時,密碼未經加密,經過 attempt() 得到 false如果使用 web/session 方式,可以用密碼為明碼吧?!
<?php
public function login(Request $request)
    {
        $credential = $this->validate($request, [
            'mobile'    => ['required', 'email', 'max:255'],
            'password' => ['required', 'alpha_num', 'min:4', 'max:8'],
        ]);
    
        // 認證成功會給予token、認證不成功會給你false
        $token = Auth::attempt($credential);
        // 取得目前登入的使用者資訊
        $user = Auth::user();
       
        abort_if(!$token, Response::HTTP_BAD_REQUEST, '帳號密碼錯誤');
        return response(['data' => $token, 'user' => $user]);
    }
login() 的 Auth::attempt($credential),也就是不管是 api/jwt 或 web/session 加密後的密碼,才能通過 attempt(),若使用明碼通過 attempt() 則會得到 false
attempt() 將上述 $credential 陣列中的值,用來在資料庫資料表中尋找使用者。因此,在上方的範例中,使用者會依照 mobile 欄位中的值來取得。若找到該使用者,則會將資料庫中儲存的密碼雜湊跟陣列中的 password 值進行比對。
 
Logout 的前提必須是 "登入" 狀態,當使用者在 "登入" 狀態下,會有一組 JWT token,清除使用者的認證狀態(JWT 工具產生的 token),即為使使用者登出
middleware('auth:member') 確認是 "登入" 狀態,才能允許他們繼續訪問 Route::post('logout', ..略)
127.0.0.1:8083/v1/members/logout
<?php
Route::middleware(['auth:member'])->group(function () {
    Route::post('/members/logout', [AuthController::class, 'logout']);
});
Auth::logout(),它會清除使用者的認證狀態(JWT 工具產生的 token),促使 使用者登出return response()->noContent() 會回傳一個 HTTP 狀態碼為 204 No Content 的回應給客戶端,代表成功執行但不需要回傳任何資料
<?php
 public function logout()
    {
        // 清除使用者的認證狀態(JWT 工具產生的 token)
        Auth::logout();
        return response()->noContent();
    }
 
call api 的 JWT 類似金手指的概念,它提供 call api 所需的認證,經由設定 config/auth.php 和 Member model implements JWTSubject ,在 AuthController 內,用 Auth:: 來使用 JWT 的功能,例如:
Auth::attempt($credential), Auth::logout(), Auth::user() 等功能1 [Day 27] Call API use JWT in Laravel: 簡介 和 安裝
2 Laravel #Manually Authenticating Users