中间件组必须在 app/Http/Kernel.php 的 $middlewareGroups 中注册后才能在路由中使用 middleware('admin'),否则报「Undefined middleware group」;组内只允许无参中间件类名字符串,带参中间件(如 throttle:60,1)须在路由级单独绑定。

中间件组在 app/Http/Kernel.php 里注册
中间件组不是写在路由文件里定义的,而是在内核类中集中声明。不先注册,路由里用 middleware('admin') 会直接报错:「Undefined middleware group」。
打开 app/Http/Kernel.php,找到 $middlewareGroups 数组,在 web 或 api 下添加新组:
protected $middlewareGroups = [
'web' => [
// ...原有中间件
'admin' => [
\App\Http\Middleware\CheckAdmin::class,
\Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
],
],
];
- 组名(如
admin)必须是字符串键,不能是数字索引 - 组内中间件顺序重要:靠前的中间件先执行,比如鉴权要放在日志记录之前
- 别把中间件类路径写错——常见错误是漏掉
\App\Http\Middleware\前缀或拼错类名
路由里用 middleware() 方法套用中间件组
注册完后,才能在 routes/web.php 或 routes/api.php 中使用。注意语法:不是 ->middleware('admin') 单独调用,而是作为链式方法接在 Route::group() 或单个路由后面。
对一组路由统一加中间件组:
Route::middleware('admin')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::post('/users', [UserController::class, 'store']);
});
对单个路由加中间件组:
Route::get('/settings', [SettingController::class, 'edit'])->middleware('admin');
-
middleware('admin')和middleware(['admin'])效果一样,但前者更简洁;传数组只在混用组和单个中间件时才需要,比如['admin', 'throttle:60,1'] - 别在
Route::group(['middleware' => 'admin'], ...)这种旧写法里用——Laravel 5.3+ 已弃用数组形式的中间件配置 - 如果路由没生效,先
php artisan route:list看输出里对应路由的Middleware列是否真显示了admin
中间件组里混用中间件实例和类名要注意构造参数
中间件组里通常写类名字符串,但如果某个中间件需要运行时参数(比如限流中间件),就不能直接写类名,得用闭包或提前实例化。
错误写法(会报 Class does not exist):
'throttle:60,1'
正确做法是:在 $middlewareGroups 里只放无参中间件;带参的放到具体路由上,用链式调用:
Route::middleware(['admin'])->group(function () {
Route::get('/api/data', [DataController::class, 'index'])
->middleware('throttle:60,1');
});
- 所有带冒号参数的中间件(如
auth:api、throttle:10,1)都不能放进$middlewareGroups的数组值里 -
auth是个特例:它本身是中间件别名,实际指向\Illuminate\Auth\Middleware\Authenticate,所以'auth'可以进组;但'auth:api'不行 - 自定义中间件如果带
__construct()参数,也必须走路由级绑定,不能进组
中间件组不会自动继承父组,嵌套需显式声明
比如你希望 admin 组同时包含 web 组所有中间件 + 额外几个,Laravel 不会自动合并。写成 'admin' => ['web', CheckAdmin::class] 是错的——'web' 在这里会被当做一个中间件类名去找,而不是展开为中间件列表。
真要复用,得手动展开:
'admin' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// ...复制 web 组全部中间件
\App\Http\Middleware\CheckAdmin::class,
],
- 这种复制维护成本高,建议只在差异小、组数少时这么做
- 如果项目里有大量组合需求,更适合用中间件链式调用 + 抽取公共路由组函数,而不是堆砌中间件组
- 别指望
middleware(['web', 'admin'])能让两个组叠加生效——它们是并列执行,不是嵌套,web组里的 session 启动逻辑不会因加了admin就多执行一遍
Kernel.php 没清缓存,或者把带参中间件硬塞进组里,然后花半小时查 route:list 输出却忽略 Middleware 列根本没变。



















