Laravel 8重写默认EnsureEmailIsVerified中间件不触发如何解决
问题根因
你将verified中间件挂载到了登录路由上,而Laravel中间件的执行时机是控制器代码执行前,此时你还未在控制器中完成账号密码校验、用户身份识别的逻辑,$request->user()永远返回null,因此你写的中间件判断条件永远不会命中邮箱未验证的分支,自然不会触发校验。
解决方案
可根据你的业务需求二选一:
方案1:在登录环节拦截未验证邮箱的用户
如果你要在登录时就直接拦截邮箱未验证的用户,两种实现方式可选:
- 推荐继续将校验逻辑保留在登录控制器中:登录环节本身就是身份校验的流程,在校验完账号密码有效性后再判断邮箱状态,是最符合逻辑的实现,不需要额外调整。
- 如果一定要将逻辑抽离为中间件,需要调整中间件逻辑,先完成账号密码校验再判断邮箱状态:
public function handle(Request $request, Closure $next): mixed { // 先校验账号密码有效性 if (!Auth::attempt($request->only('email', 'password'))) { return response()->json(['message' => '账号或密码错误'], 401); } $user = Auth::user(); // 校验邮箱状态 if ($user instanceof MustVerifyEmail && !$user->hasVerifiedEmail()) { Auth::logout(); // 清除刚才生成的登录状态 return response()->json([ 'message' => 'You need to confirm your account. We have sent you an activation link to your email.' ], 422); } return $next($request); }
调整后登录路由挂载该中间件即可,控制器中无需重复做账号密码和邮箱状态校验。
方案2:登录后访问业务接口时校验邮箱状态
这是Laravel官方verified中间件的标准使用方式,符合REST API的常见设计规范:用户可以正常完成登录流程拿到身份凭证,但调用所有业务接口时会校验邮箱状态,未验证用户无法访问业务接口。
路由配置示例:
// 公开路由,无需登录即可访问 Route::post('login', [Auth\AuthenticationController::class, 'login']); // 需登录且邮箱已验证才能访问的业务路由 Route::middleware(['auth:sanctum', 'verified'])->group(function () { // 所有需要权限的业务接口都放在该分组下 Route::get('/user/profile', function (Request $request) { return $request->user(); }); });
注意事项
- 确认你的
User模型已经实现了MustVerifyEmail接口,否则中间件中$request->user() instanceof MustVerifyEmail判断永远为false,会导致校验不触发。 - 如果你使用的是JWT等非官方身份认证驱动,确认
auth中间件已经正确配置,能够正常解析请求中的身份凭证获取用户对象。
内容的提问来源于stack exchange,提问作者BigJobbies
相关产品推荐
相关产品推荐

