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
数据填充
- 填充前准备
执行填充
php artisan db:seed
- 填充前准备
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_SECRETphp 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', ],
认证测试
- 密码错误时
- 更新并获取数据库
ID=1
的密码用于测试 - 用正确的密码尝试获取
access_token
- 用
access_token
获取用户信息
当你不想使用默认的email
作为用户名时
- 测试
访问节流限制
- 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'); }); });
测试
- 同一分钟请求第一次
- 同一分钟请求第二次
当然你如果认为
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 ); }); } }
- 首先在
Comment here is closed