延續 Lumen – Laravel 微型框架使用 JWT 這篇筆記,加上自動更新 Token,從 Laravel – JWT 自動更新 Token 改成適合 Lumen 使用的 JWT 自動更新 Token。

新增 jwtRefresh Middle

php artisan make:middleware jwtRefresh
<?php

namespace App\Http\Middleware;

use Closure;
use Exception;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException as TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException as TokenExpiredException;
use Illuminate\Contracts\Auth\Factory as Auth;

class JwtRefreshToken extends BaseMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        try {
            //檢查是否有使用者通過驗證
            $user = $this->auth->parseToken()->authenticate();
            // //Token TTL 到期時間
            // $expireTime = JWTAuth::payload()['exp'];
            // // 如果 Token 到期時間小於5分鐘,重新產生一個新的 Token 並附帶在 header 送出,讓前端重新抓取.
            // if (($expireTime - time()) < 5*60 && ($expireTime - time()) > 0) {
            //     $refreshed = JWTAuth::refresh(JWTAuth::getToken());
            //     $user = JWTAuth::setToken($refreshed)->toUser();
            //     $request->headers->set('Authorization', 'Bearer '.$refreshed);

            //     // 輸出到BODY測試
            //     return response()->json([
            //         'code' => 200,
            //         'user' => $user,
            //         'access_token' => $refreshed,
            //         'token_type' => 'bearer',
            //         'expires_in' => JWTAuth::factory()->getTTL(),
            //     ]);
            // }

        } catch (Exception $e) {
            //檢查 Token 是否無效
            if ($e instanceof TokenInvalidException){
                $status     = 401;
                $message    = 'This token is invalid. Please Login';
                return response()->json(compact('status','message'),401);
            //檢查 Token 是否到期
            }else if ($e instanceof TokenExpiredException){
                try
                {
                    // 如果 Token 到期,重新產生一個新的 Token 並附帶在 header 送出,讓前端重新抓取.
                    $refreshed = $this->auth->refresh($this->auth->getToken());
                    $user = $this->auth->setToken($refreshed)->toUser();
                    $request->headers->set('Authorization','Bearer '.$refreshed);

                    //輸出到BODY測試
                    //return response()->json([
                    //    'code' => 200,
                    //    'user' => $user,
                    //    'access_token' => $refreshed,
                    //    'token_type' => 'bearer',
                    //    'expires_in' => $this->auth->factory()->getTTL(),
                    //]);

                }catch (JWTException $e){
                    // Token 無法被 refresh
                    return response()->json([
                        'code'   => 103,
                        'message' => 'Token cannot be refreshed, please Login again'
                    ]);
                }
            }else{
                //找不到 Token.
                $message = 'Authorization Token not found';
                return response()->json(compact('message'), 404);
            }
        }
        return $next($request);
    }
}

修改 bootstrap\app.php 註冊 jwtRefresh Middleware

$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class,
    //Jwt Token Auto Refresh Middleware
    'jwtRefresh' => App\Http\Middleware\JwtRefreshToken::class,
]);

修改 UserLoginController

    public function __construct()
    {
        //除了 login 其餘 function 都要經過 api 的 middleware 檢查
        $this->middleware('auth:api', ['except' => ['login']]);
        //除了 login 其餘 function 都要經過 jwtRefresh 的 middleware 檢查 token
        $this->middleware('jwtRefresh', ['except' => ['login']]);
    }

修改 Authenticate Middleware (Auth)

    public function handle($request, Closure $next, $guard = null)
    {
        // 將使用者判斷註解關閉或移除
        // if ($this->auth->guard($guard)->guest()) {
        //     return response('Unauthorized.', 401);
        // }

        return $next($request);
    }

成品同步放在我的 GitHub

最後修改日期: 2020 年 12 月 14 日