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