这更像是一个学术问题,而不是现实世界的问题,尽管当我在中间件配置错误的遗留 5.2 项目中遇到它时,它让我感到困惑,并且它的行为在 Laravel 11 中没有改变。虽然也有人提出了类似的问题在互联网上,结果总是有人忘记在失败的中间件之前移动适当的中间件。这是不一样的。
一些上下文:开箱即用,Laravel 附带全局、“web”和“api”中间件组。 一旦用户通过基于 cookie 的常规会话进行身份验证,
\Illuminate\Cookie\Middleware\EncryptCookies::class
和 \Illuminate\Session\Middleware\StartSession::class
中间件是加载该用户以通过 auth()->user()
或 $request->user()
访问所需的唯一内容。这些中间件作为默认“web”组的一部分包含在内。
中间件按照列出的顺序依次执行。全局中间件总是首先执行。然而,将上述“Web”中间件提升到全局仍然有效,但当从之后调用的全局中间件引用时,会导致
$request->user()
变为 null
。换句话说:
// app/Http/Middleware/Test.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class Test
{
public function handle(Request $request, Closure $next)
{
dd($request->user()); // `null` when global and `App\Models\User` when not
dd(auth()->user()); // This always works
}
}
这是其余的代码:
// bootstrap/app.php
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
)
->withMiddleware(function (Middleware $middleware) {
// This doesn't work...
$middleware->use([
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\Test::class,
]);
$middleware->group('web', []); // Clear out default web middleware
// But this works...
$middleware->use([
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
]);
$middleware->group('web', [
\App\Http\Middleware\Test::class,
]);
// And this also works...
$middleware->use([]); // Clear out default global middleware
$middleware->group('web', [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\Test::class,
]);
})
->create();
// routes/web.php
<?php
use Illuminate\Support\Facades\Route;
Route::get('', fn() => 'It works!');
我对 Laravel 源代码进行了一些挖掘,但很快就陷入了困境。值得注意的是,
$request->user()
始终由StartSession
这一行的时间设置,无论它是否是全局的。
我很满意这种行为是一致的并且似乎是有意为之,但我希望有更多知识的人可以解释为什么会这样。
据我所知,要使用
$request->user()
,session middleware必须在此之前执行过。
独立于请求的初始化状态工作,因为它直接与身份验证服务交互。auth()->user()
依赖于request对象,需要会话中间件先初始化session($request->user()
)StartSession
\Illuminate\Session\Middleware\StartSession::class,