laravel 自定义中间件实现身份验证

2023-04-16 16:28:17 浏览数 (1)

通过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中间件

代码语言:javascript复制
    protected $routeMiddleware = [
        'auth' => AppHttpMiddlewareAuthenticate::class,
    ...
    ];

//比如
Route::group(['middleware' => ['auth:sanctum']], function () {}

但在SPA 认证场景下也会使用api中间件组

代码语言:javascript复制
    protected $middlewareGroups = [
    ...
        'api' => [
            LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful::class,
    ...
        ],
    ];

二、JWT使用的也是auth中间件

代码语言:javascript复制
    protected $routeMiddleware = [
        'auth' => AppHttpMiddlewareAuthenticate::class,
    ];

//比如
$this->middleware('auth:api', ['except' => ['login']]);

自定义中间件

该中间件支持多端,比如用户端和管理员端

vi app/Http/Middleware/ApiAuth.php

代码语言:javascript复制
<?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配置一下

代码语言:javascript复制
    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(){}

0 人点赞