使用 middleware('auth:admin') 在路由中指定 guard 是最清晰方式,handle() 中接收 $guard 参数并调用 auth::guard($guard)->user() 动态鉴权,所有动态数据必须在 handle() 中处理,不可在构造函数中获取。

多表用户(如 admin、customer、vendor)使用 JWT 鉴权时,中间件需区分用户类型并动态加载对应模型和 guard。参数传递不能靠构造函数,必须在 handle() 方法中接收并结合请求上下文解析,核心是“路由标识 + 请求属性 + 参数语法”三者配合。
用 middleware('auth:admin') 明确指定用户表
在路由中直接传入 guard 名称,是最清晰、最符合 Laravel 原生习惯的方式:
-
路由写法:
->middleware('auth:admin')或->middleware(['auth:customer']) -
中间件 handle() 接收:第三个参数
$guard自动拿到字符串'admin',无需额外解析 -
实际校验逻辑:调用
Auth::guard($guard)->user(),自动切换到对应 guard 配置(如guards.admin.driver = jwt) -
注意:确保
config/auth.php中已定义各 guard,并关联正确的 provider(如providers.admin.model = App\Models\Admin)
传多个参数时用逗号分隔并严格对齐形参
当需要同时指定用户类型和权限动作(如仅允许 admin 编辑特定资源),可扩展为双参数:
-
路由写法:
->middleware('auth:admin,update:post')—— 注意:冒号只用于分隔中间件名与首参,后续逗号分隔全部视为独立字符串参数 -
中间件签名要匹配:
public function handle($request, Closure $next, $guard, $action, $resource) -
参数值全是字符串:
$guard = 'admin',$action = 'update',$resource = 'post';不可依赖自动类型转换 -
安全校验示例:先通过
Auth::guard($guard)->user()获取用户,再调用$user->can($action, $resource)(需确保模型实现了Authorizable)
避免在构造函数里尝试获取路由参数或 JWT 载荷
构造函数执行时机早于请求解析,无法访问 $request、JWT token、路由参数或 guard 实例:
-
错误做法:
public function __construct($guard) { ... }→ 容器无法注入,报Target [string] is not instantiable -
正确路径:所有动态数据(包括从 JWT payload 提取的
user_type字段)都应在handle()中处理 -
读取 JWT 载荷:用
$token = $request->bearerToken()+JWTAuth::setToken($token)->getPayload()(若用 tymon/jwt-auth),再取['user_type'] ?? null -
配合路由参数更稳妥:例如
/api/admins/{id},可在handle()中用$request->route()?->parameter('id')结合$guard参数做归属校验
复杂场景用闭包中间件绑定运行时值
当参数需从数据库查出(如租户下可用角色列表)、或需结合当前请求头动态计算时,闭包中间件更灵活:
-
路由中写法:
->middleware(function ($request, $next) { $allowedGuards = config('app.multi_auth_guards'); return app(MultiAuthMiddleware::class, ['guards' => $allowedGuards])->handle($request, $next); }) -
关键点:
app(XXX::class, [...])手动解析类,支持向构造函数传数组参数(仅限此方式) - 适用场景:SAAS 多租户系统中,每个租户启用不同的用户表组合;或灰度环境按 header 切换鉴权策略
- 缺点:无法复用中间件别名,不适合全局注册,仅推荐单点强定制逻辑











