通过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' => AppHttpMiddlewareAuthenticate::class,
...
];
//比如
Route::group(['middleware' => ['auth:sanctum']], function () {}
但在SPA 认证
场景下也会使用api
中间件组
protected $middlewareGroups = [
...
'api' => [
LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful::class,
...
],
];
二、JWT
使用的也是auth
中间件
protected $routeMiddleware = [
'auth' => AppHttpMiddlewareAuthenticate::class,
];
//比如
$this->middleware('auth:api', ['except' => ['login']]);
自定义中间件
该中间件支持多端,比如用户端和管理员端
vi app/Http/Middleware/ApiAuth.php
<?php
namespace AppHttpMiddleware;
use Closure;
use IlluminateSupportFacadesRedis;
class ApiAuth {
public $key='{role}.{id}.token';
/**
* api鉴权中间件
* @param $request
* @param Closure $next
* @param $role
* @return IlluminateContractsFoundationApplication|IlluminateContractsRoutingResponseFactory|IlluminateHttpResponse|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' => AppHttpMiddlewareApiAuth::class,
];
在路由中使用
代码语言:javascript复制#用户端
Route::group(['prefix' => 'user', 'middleware'=>['auth.api:user']], function(){}
#管理员端
Route::group(['prefix' => 'admin', 'middleware'=>['auth.api:admin']], function(){}