laravel 自定义中间件实现身份验证
通过Laravel 用户认证我们知道了基于 api 的身份验证,实现方式有Laravel Sanctum API 授权 、 Laravel 使用 Json Web Token(JWT) 等,今天介绍一下自定义中间件实现身份验证
中间件
使用中间件需要提前在app/Http/Kernel.php这里配置,分为全局中间件、中间件、中间件组
全局中间件
全局中间件无需主动调用,系统会自动应用到每次请求。比如:TrimStrings中间件会自动去掉请求参数左右两边的空格;ConvertEmptyStringsToNull中间件会自动把请求参数中的空字符串转为 null。
ConvertEmptyStringsToNull中间件建议不要开启,空字符串和 null 类型不同要区分开。我们之前就遇到一个坑:一个支持关键词搜索的列表,参数校验为'keyword'   => 'string',,因为启用了该中间件,传空字符串时报错了,The keyword must be a string
按照我们通常理解关键词可以传(string),也可以不传(null);这里可以传又分为空字符串和有值的字符串
- 
不启用该中间件,传空字符串:参数校验 'keyword' => 'string',,通过参数校验,我拿到空字符串。。。
- 
启用该中间件,传空字符串:参数校验 'keyword' => 'string|nullable',,通过参数校验,我拿到null值。。。
最终我选择不启用该中间件
中间件、中间件组
一、上面提到的Laravel Sanctum API 授权使用的是auth中间件
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
	...
    ];
//比如
Route::group(['middleware' => ['auth:sanctum']], function () {}
但在SPA 认证场景下也会使用api中间件组
    protected $middlewareGroups = [
	...
        'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
	...
        ],
    ];
二、JWT使用的也是auth 中间件
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
    ];
//比如
$this->middleware('auth:api', ['except' => ['login']]);
自定义中间件
该中间件支持多端,比如用户端和管理员端
vi app/Http/Middleware/ApiAuth.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Redis;
class ApiAuth {
    public $key='{role}.{id}.token';
    /**
     * api鉴权中间件
     * @param $request
     * @param Closure $next
     * @param $role
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|mixed
     */
    public function handle($request, Closure $next, $role) {//$role=user/admin
        $token=$request->header('token', '');
        if(empty($token)){
            return response(['msg'=>'未传递token,请重新登录'], 403);
        }
        $_token=Redis::get(str_replace(['{role}', '{id}'], [$role, $request->route($role.'_id')], $this->key));
        if (empty($_token)) {
            return response(['msg'=>'token已失效,请重新登录'], 401);
        }
        if($token !==$_token){
            return response(['msg'=>'未通过验证,请重新登录'], 401);
        }
        return $next($request);
    }
}
在app/Http/Kernel.php配置一下
    protected $routeMiddleware = [
	...
        'auth.api' => \App\Http\Middleware\ApiAuth::class,
    ];
在路由中使用
#用户端
Route::group(['prefix' => 'user', 'middleware'=>['auth.api:user']], function(){}
#管理员端
Route::group(['prefix' => 'admin', 'middleware'=>['auth.api:admin']], function(){}
