使用 JWT 构建基本的 Api 登录接口

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 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2

jwt-auth好像不维护了,可以考虑用laravel Sanctum

2年前 评论
王小大 (楼主) 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!