使用 JWT 構建基本的 Api 登入介面

王小大發表於2021-11-09

JWT` 安裝

  1. 安裝 JWT

    composer require tymon/jwt-auth
  2. 釋出配置

    php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
  3. 生成加密秘鑰

    php artisan jwt:secret
  4. 更新模型

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    use Illuminate\Notifications\Notifiable;
    use Laravel\Sanctum\HasApiTokens;
    use Tymon\JWTAuth\Contracts\JWTSubject;
    
    class User extends Authenticatable implements JWTSubject
    {
        use HasApiTokens, HasFactory, Notifiable;
    
        public function getJWTIdentifier()
        {
            return $this->getKey();
        }
    
        public function getJWTCustomClaims()
        {
            return [];
        }
    }
    
  5. 修改 config/app.php 增加如下兩條Facades

    當然這裡可以不用註冊, 直接使用助手函式 auth()

    'aliases' => [
        ......
    
        'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
        'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ],
  6. 修改 config/auth.php 修改或增加 guards

    如果是多使用者表還需修改當前檔案中 providers

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    
        // 增加如下 driver->jwt
        'user' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],
  7. 最後在 .env 末尾增加如下兩條配置

    有效時間: 是指在x分鐘內可以憑藉 token 獲取內容

    重新整理時間: 是指在x分鐘內可以憑藉舊 token 換取新 token , 直到重新整理超過重新整理時間後, 需重新獲取無法再使用舊 token 換取新 token

    JWT_TTL=1440             // 有效時間(單位: 分鐘)
    JWT_REFRESH_TTL=20160    // 重新整理時間(單位: 分鐘)

登入部署

  1. 建立控制器

     php artisan make:controller Backend/AuthenticationController
  2. 建立 request

     php artisan make:request Backend/UserRequest
  3. 建立 resource

     php artisan make:resource Backend/UserResource
  4. 編寫路由

     <?php
    
     use App\Http\Controllers\Backend\AuthenticationController;
     use Illuminate\Support\Facades\Route;
    
     /**
      * 後臺免認證路由組
      */
     Route::prefix('backend')->name('backend.')->group(function () {
         Route::post('login', [AuthenticationController::class, 'login'])->name('authentication.login');
     });
    
     /**
      * 後臺需要認證路由組
      */
     Route::prefix('backend')->name('backend.')->middleware(["auth:user"])->group(function () {
         Route::get('refresh', [AuthenticationController::class, 'refresh'])->name('authentication.refresh');
         Route::delete('logout', [AuthenticationController::class, 'logout'])->name('authentication.logout');
     });
  5. 建立輔助函式檔案

     touch app/helper.php
  6. composer 自動載入

     "autoload": {
         ...
         "files": [
             "app/helper.php"
         ]
     },
     composer dump-autoload
  7. 修改 app/helper.php 增加三個函式, 這個也可以自己封裝

     <?php
    
     if (!function_exists('send')) {
         /**
          * 請求成功響應,可以返回一個字串或者一個陣列
          * @param mixed $message 字串或者陣列
          * @param int $status 狀態碼
          * @return \Illuminate\Http\JsonResponse
          */
         function send($message, int $status = 200)
         {
             return \Response::json($message, $status);
         }
     }
    
     if (!function_exists('send_message')) {
         /**
          * 字串響應,用於傳送字串
          * @param string $message 內容
          * @param int $status 狀態碼
          * @return \Illuminate\Http\JsonResponse
          */
         function send_message($message, int $status = 400, $code = null)
         {
             $code = $code ?: $status;
             return \Response::json(['message' => $message, 'code' => $code], $status);
         }
     }
    
     if (!function_exists('no_content')) {
         /**
          * 空響應
          * @param int $status 狀態碼
          * @return \Illuminate\Http\Response
          */
         function no_content(int $status = 204)
         {
             return \Response::noContent($status);
         }
     }
    
  8. 編寫 AuthenticationController 控制器中 登入/重新整理/退出 方法

     <?php
    
     namespace App\Http\Controllers\Backend;
    
     use App\Http\Controllers\Controller;
     use App\Http\Requests\Backend\UserRequest;
     use App\Http\Resources\Backend\UserResource;
     use App\Models\User;
     use Illuminate\Http\Response;
    
     class AuthenticationController extends Controller
     {
         public function login(UserRequest $request)
         {
             $username = $request->input('username');
             $password = $request->input('password');
    
             $user = User::whereName($username)->first();
    
             if (!$user) {
                 return send_message("賬號不存在", Response::HTTP_UNPROCESSABLE_ENTITY);
             }
    
             $token = auth('user')->attempt(compact(['username', 'password']));
             if (!$token) {
                 return send_message("賬號和密碼不匹配", Response::HTTP_UNPROCESSABLE_ENTITY);
             }
    
             return send([
                 'token'     => $token,
                 'expire_in' => auth('user')->factory()->getTTL() * 60,
                 'info'      => new UserResource($user)
             ]);
         }
    
         public function refresh()
         {
             $token = auth()->refresh();
             return send([
                 'token'     => $token,
                 'expire_in' => auth()->factory()->getTTL() * 60,
             ]);
         }
    
         public function logout()
         {
             auth()->logout();
             return no_content();
         }
     }
  9. 修改中介軟體

     <?php
    
     namespace App\Http\Middleware;
    
     use Illuminate\Auth\Middleware\Authenticate as Middleware;
     use Illuminate\Http\Response;
    
     class Authenticate extends Middleware
     {
         /**
          * Get the path the user should be redirected to when they are not authenticated.
          *
          * @param  \Illuminate\Http\Request  $request
          * @return string|null
          */
         protected function redirectTo($request)
         {
             // if (! $request->expectsJson()) {
             //     return route('login');
             // }
    
             return send_message('未認證,請先登入', Response::HTTP_UNAUTHORIZED);
         }
     }

    建議自己捕獲一下異常

常用擴充套件

  • 檔案上傳

     composer require littledragoner/file-manager
  • Laravel 漢化

    composer require overtrue/laravel-lang
  • 列舉型別

    composer require bensampo/laravel-enum
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章