在 Laravel 中,似乎没有立即应用中间件

In Laravel, it seems the middleware is not applied immediately

我用Laravel 9.

我有这条路由,包含在一个组和中间件中:

Route::middleware(['auth', 'ensureUserIsAdmin'])->group(function () {
    .....
    Route::resource('sports', SportController::class);
    .....
});

中间件只是检查用户是否是管理员。

当连接的用户不是管理员,并尝试前往此路线进行 已知 运动时:

/sports/FOOT/edit

然后他收到响应“FORBIDDEN”。完美,中间件完成了他的工作。

但是当同一个非管理员用户尝试前往 未知 运动的路线时:

/sports/UNKNOWSPORT/edit

然后他收到“未找到”的回复。正常吗?看起来框架发出了一个数据库请求,并且只有在他应用中间件之后。

我的代码有什么问题?

web.php 文件中的每个路由都由 web 组中间件处理 - 您可以在 RouteServiceProvider class

中找到它
Route::middleware('web')
        ->group(base_path('routes/web.php'));

该组在 Kernel class 中定义并包含一些应用程序中间件。它们在任何特定于路由的中间件触发之前被处理

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

所以当你认为你的路线有 'auth', 'ensureUserIsAdmin' 作为中间件时,这是不正确的

在您的情况下,\Illuminate\Routing\Middleware\SubstituteBindings::class 中间件失败并显示 404。是的,如果其中有一些路由参数,它会查询数据库

为简单起见,假设您有这条路线并且只存在 id=1 的模型

Route::get('/sports/{sport}', function (Sport $sport) {
    dump($sport);
});

/sports/1是倾销模型,sports/2显示404符合预期。让我们评论\Illuminate\Routing\Middleware\SubstituteBindings::class

现在两个页面实际上都是转储模型,但是sports/2显示没有参数的空默认模型

如果您需要更改此逻辑并为 non-existing 模型显示 403,您可以将中间件添加到组 BEFORE \Illuminate\Routing\Middleware\SubstituteBindings::class中间件

例如,让我们创建简单的中间件,它总是 return 403

public function handle(Request $request, Closure $next)
{
    abort(403);
}

并将web组更改为

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        AlwaysFalse::class, // HERE I AM
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

现在无论两个页面都会显示什么403

但是这将应用于 routes/web.php 文件中的 EVERY 路由,因此您可以像

这样更改逻辑
public function handle(Request $request, Closure $next)
{
    // Applied only in any route named `sports.something` - resource routes including
    // is_admin() function doesn't really exists, middleware logic is up to you
    abort_if((Route::is('sports.*') && !is_admin()), 403);

    return $next($request);
}

现在管理员用户 /sports/1 显示模型,/sports/2 - 404 响应。 对于 non-admin 用户,两个页面都将 return 403.

关于这是否正常 - 我认为是的。问问自己——对于一个根本不存在的东西,你能做什么(你的访问级别)?所以最好先定义模型是否真的存在,在你确定它存在之后,用它做点什么。但这只是我的意见,有人可能不同意

希望对您有所帮助