laravel 相关

  • 安装 laravel 框架,版本根据自己的实际情况选择

    composer create-project --prefer-dist laravel/laravel laravel "8.5.*"
  • .env文件中配置数据库连接

    DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=De5RJZWSjJF42FkC
  • 数据库迁移

    # 在项目根目录执行 php artisan migrate
  • 数据填充

Dingo Api 相关

  • 安装 Dingo Api

    composer require "dingo/api"
  • 在 config 目录生成配置文件api.php

    php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"
  • .env文件里配置Dingo Api , Dingo API 配置项说明

    # dingo api API_STANDARDS_TREE=x // 环境 API_SUBTYPE=myapp // 子类型 API_PREFIX=api // 前缀 API_DOMAIN=api.myapp.com // 域名 API_VERSION=v1 // 版本号 API_NAME="My API" // 名字 API_CONDITIONAL_REQUEST=false // 条件请求 API_STRICT=false // 严格模式 API_DEFAULT_FORMAT=json // 响应格式 API_DEBUG=true // 调试模式

JWT 相关

  • 安装 jwt-auth ,参考文档 jwt-auth 文档

    composer require "tymon/jwt-auth"
  • 在 config 目录生成配置文件jwt.php

    php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
  • .env中生成加密所需字符串 JWT_SECRET

    php artisan jwt:secret
  • 修改你的 app/Models/User.php

    <?php namespace App\Models; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use HasFactory, Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * The attributes that should be cast to native types. * * @var array */ protected $casts = [ 'email_verified_at' => 'datetime', ]; public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } }
  • 修改 config/auth.php

    'defaults' => [ 'guard' => 'api', 'passwords' => 'users', ], ... 'guards' => [ 'api' => [ 'driver' => 'jwt', 'provider' => 'users', ], ],
  • 修改 routes/api.php , 由Dingo 接管

    <?php $api = app('Dingo\Api\Routing\Router'); $api->version('v1', ['namespace' => 'App\Http\Controllers\Api\v1'], function ($api) { $api->get('password', 'AuthController@password')->name('password'); $api->post('login', 'AuthController@login')->name('login'); $api->group(['middleware' => 'api.auth'], function ($api) { $api->post('logout', 'AuthController@logout'); $api->post('refresh', 'AuthController@refresh'); $api->post('me', 'AuthController@me')->name('me'); }); });
  • 创建 基础控制器、用户认证控制器,对应路由文件中的命名空间 App\Http\Controllers\Api\v1

    • Controller

      <?php namespace App\Http\Controllers\Api\V1; use Dingo\Api\Routing\Helpers; use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { use Helpers; }
    • AuthController

      <?php namespace App\Http\Controllers\Api\V1; use App\Models\User; class AuthController extends Controller { public function password() { $password = bcrypt('123456'); User::find(1)->update(['password' => $password]); return response()->json(['password' => 123456]); } /** * Get a JWT via given credentials. * * @return \Illuminate\Http\JsonResponse */ public function login() { $credentials = request(['email', 'password']); if (! $token = auth()->attempt($credentials)) { return response()->json(['error' => 'Unauthorized'], 401); } return $this->respondWithToken($token); } /** * Get the authenticated User. * * @return \Illuminate\Http\JsonResponse */ public function me() { return response()->json(auth()->user()); } /** * Log the user out (Invalidate the token). * * @return \Illuminate\Http\JsonResponse */ public function logout() { auth()->logout(); return response()->json(['message' => 'Successfully logged out']); } /** * Refresh a token. * * @return \Illuminate\Http\JsonResponse */ public function refresh() { return $this->respondWithToken(auth()->refresh()); } /** * Get the token array structure. * * @param string $token * * @return \Illuminate\Http\JsonResponse */ protected function respondWithToken($token) { return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth()->factory()->getTTL() * 60 ]); } }

配置 Dongo API 的Auth认证使用JWT

  • config/api.php

    'auth' => [ 'jwt' => 'Dingo\Api\Auth\Provider\JWT', ],

认证测试

当你不想使用默认的email 作为用户名时

editParams.png

editParams.png

访问节流限制

  • Dingo API 默认节流限速是绑定客户 ip 地址的。如果需要自定义节流限速方法,需要注册你自己的解决者。
  • 新建 app/Http/Middleware/MyThrottle.php, 例如我这里以openid为标识节流限速

    <?php namespace App\Http\Middleware; use Dingo\Api\Contract\Http\RateLimit\HasRateLimiter; use Dingo\Api\Http\RateLimit\Throttle\Throttle; use Dingo\Api\Http\Request; use Illuminate\Container\Container; class MyThrottle extends Throttle implements HasRateLimiter { /** * @param Container $container * @return bool */ public function match(Container $container): bool { return $container['api.auth']->check(); } public function getRateLimiter(Container $app, Request $request): string { $user = auth()->user(); return $user->openid; } }
  • 在 routes/api.php 使用

    <?php use App\Http\Middleware\MyThrottle; $api = app('Dingo\Api\Routing\Router'); $api->version('v1', ['namespace' => 'App\Http\Controllers\Api\v1'], function ($api) { $api->group(['middleware' => 'api.auth'], function ($api) { $api->get('limit', [ 'middleware' => 'api.throttle', 'throttle' => new MyThrottle(['limit' => 1, 'expires' => 1]), //一分钟一次请求 'uses' => 'AuthController@limit' ])->name('limit'); }); });
  • 测试

    • 同一分钟请求第一次

    limit-pass.png

    limit-pass.png

    • 同一分钟请求第二次

    limit-err.png

    limit-err.png

  • 当然你如果认为Dingdo APi 抛出的异常不美观,你也可以捕获 Dongo API 错误进行自定义配置

    • 首先在 app/Exceptions/Dingo.php 文件用于处理自定义
    <?php <?php namespace App\Exceptions; use Exception; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; class Dingo extends ExceptionHandler { /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $exception * @return \Illuminate\Http\Response */ public function render($request, Exception|\Throwable $exception) { if (get_class($exception) == 'Dingo\Api\Exception\RateLimitExceededException') { return response()->json([ 'message' => '请勿频繁提交!!' ],429); } return parent::render($request, $exception); } }
    • app/Providers/AppServiceProvider.php 中注册服务
    <?php namespace App\Providers; use Illuminate\Http\Request; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { // } /** * Bootstrap any application services. * * @return void */ public function boot() { app('api.exception')->register(function (\Exception $exception) { return app('App\Exceptions\Dingo')->render( Request::capture(), $exception ); }); } }

    error.png

    error.png

Last modification:June 19, 2023
如果觉得我的文章对你有用,请随意赞赏