在 laravel 中间件中应调用 auth()->user() 或 auth('guard_name')->check() 触发懒初始化,避免直接用 auth::check();需确认默认 guard 配置、中间件注册顺序(须在 startsession 之后),并区分 web/api 场景返回对应响应。

中间件里怎么获取当前用户
在 Laravel 中间件里不能直接用 Auth::user() 判断登录状态,因为认证服务可能还没完全初始化,尤其在某些请求生命周期早期(比如路由未匹配前)会返回 null。正确做法是调用 auth()->user() 或 Auth::guard()->user(),它会触发 guard 的 lazy 初始化逻辑,更可靠。
常见错误现象:中间件里写 if (Auth::check()) { ... } 却始终为 false,其实是 guard 没显式指定,默认 guard 可能不是你预期的(比如 API 请求走的是 api guard,而你只配置了 web)。
- 确认当前请求使用的 guard:检查
config/auth.php中defaults.guard,或在中间件中用auth()->getDefaultDriver()查看 - 显式指定 guard 更稳妥:
auth('web')->check()或auth('api')->user() - 如果中间件用于 API 路由,确保已启用
auth:api中间件(或自定义 token 验证逻辑),否则auth('api')会一直失败
判断用户是否被禁用或邮箱未验证
Laravel 自带的 auth 中间件只管登录态,不校验业务状态。你需要手动补全逻辑,比如检查 $user->is_active 或 $user->hasVerifiedEmail()。
注意:Laravel 9+ 的邮箱验证默认开启,但 hasVerifiedEmail() 依赖 MustVerifyEmail trait 和对应数据库字段(email_verified_at)。如果没加这个 trait,调用会报错;如果字段不存在,会始终返回 false。
- 先确保用户模型实现了
MustVerifyEmail(如class User extends Authenticatable implements MustVerifyEmail) - 禁用状态建议统一用布尔字段(如
is_active),避免用字符串或状态码,减少中间件里类型判断 - 不要在中间件里做复杂查询(比如查角色权限表),应提前在登录时缓存或用策略类解耦
如何在中间件里重定向未登录/异常用户
中间件里不能直接 return redirect(),必须返回一个 Response 实例。最简方式是调用 redirect()->guest(...) 或 response()->view(...),否则会抛出 UnexpectedValueException。
典型错误:写 return redirect('/login'); 看似正常,但在某些 Laravel 版本(尤其是配合 API 路由时)会因响应格式不匹配导致空白页或 500 错误。
- Web 场景推荐:
return redirect()->guest(route('login'));(自动保留原 URL 到url查询参数) - API 场景必须返回 JSON:
return response()->json(['message' => 'Unauthorized'], 401); - 若需区分「未登录」和「已登录但被禁用」,建议返回不同状态码(如 401 vs 403),前端可据此做不同提示
为什么 Auth::check() 在中间件里有时失效
根本原因是 Laravel 的认证服务注册时机和中间件执行顺序。比如你在 App\Http\Kernel.php 中把自定义中间件放在 EncryptCookies 或 AddQueuedCookiesToResponse 之前,session 就还没解密或写入,Auth::check() 必然失败。
另一个常见坑:中间件用了 terminate() 方法做异步判断,但此时请求已结束,auth() 实例已被销毁,调用会返回 null。
- 检查中间件在
$middlewareGroups中的位置,确保在StartSession和Authenticate之后(除非你刻意要早于认证) - 避免在中间件构造函数里调用
Auth::check(),此时容器尚未注入完成 - 调试时可用
dd(auth()->shouldUse(), auth()->user())快速确认 guard 是否生效、用户是否加载成功











