
本文介绍了在 laravel 中如何实现一种灵活的邮件验证机制,允许访客自由访问网站内容,同时对所有已登录用户强制执行邮件验证。通过创建自定义中间件,我们可以在不影响公共页面可访问性的前提下,确保认证用户的账户安全。
在 Laravel 应用程序中,默认的邮件验证中间件 (verified) 旨在保护需要用户已验证邮箱才能访问的路由。然而,当应用程序存在一部分可供访客访问的公共页面(例如 / 或 /posts/1),同时又希望所有已登录用户在访问网站任何部分时都必须是已验证状态时,默认的 verified 中间件会带来挑战。直接将 middleware(‘verified’) 应用于所有路由会导致访客在尝试访问公共页面时也被要求登录,这与需求相悖。
解决此问题的核心思路是创建一个自定义中间件,该中间件在执行邮件验证检查之前,首先判断当前请求是否有已认证的用户。如果用户是访客,则允许其通过;如果用户已登录但邮箱未验证,则将其重定向到邮件验证通知页面。
创建自定义中间件
首先,我们需要生成一个新的中间件。可以通过 Artisan 命令来完成:
php artisan make:middleware EnsureEmailIsVerifiedUnlessGuest
然后,打开 app/Http/Middleware/EnsureEmailIsVerifiedUnlessGuest.php 文件,并修改其 handle 方法,使其包含以下逻辑:
<?php
namespace App/Http/Middleware;
use Closure;
use Illuminate/Http/Request;
use Illuminate/Support/Facades/Redirect;
use Illuminate/Support/Facades/URL;
use Illuminate/Contracts/Auth/MustVerifyEmail;
use Symfony/Component/HttpFoundation/Response;
class EnsureEmailIsVerifiedUnlessGuest
{
/**
* 处理传入请求。
*
* @param /Illuminate/Http/Request $request
* @param /Closure(/Illuminate/Http/Request): (/Symfony/Component/HttpFoundation/Response) $next
* @param string|null $redirectToRoute
* @return /Symfony/Component/HttpFoundation/Response
*/
public function handle(Request $request, Closure $next, $redirectToRoute = null): Response
{
// 检查是否存在已认证的用户
// 并且该用户模型实现了 MustVerifyEmail 接口
// 并且该用户的邮箱尚未验证
if ($request->user() &&
($request->user() instanceof MustVerifyEmail &&
! $request->user()->hasVerifiedEmail())) {
// 如果是 API 请求,返回 403 错误
if ($request->expectsJson()) {
return abort(403, '您的邮箱地址尚未验证。');
}
// 对于 Web 请求,重定向到邮件验证通知页面
return Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
}
// 如果没有认证用户,或者用户已验证,则继续请求
return $next($request);
}
}
代码解释:
- $request->user(): 判断当前请求是否存在已认证的用户。如果为 null,表示是访客。
- $request->user() instanceof MustVerifyEmail: 确保当前用户模型实现了 Illuminate/Contracts/Auth/MustVerifyEmail 接口,这是 Laravel 邮件验证功能的基础。
- ! $request->user()->hasVerifiedEmail(): 检查已认证用户的邮箱是否尚未验证。
- 如果以上三个条件都满足(即有已认证用户,该用户支持邮件验证且尚未验证),则根据请求类型进行处理:
- $request->expectsJson(): 如果是 API 请求,返回 HTTP 403 错误响应。
- Redirect::guest(URL::route($redirectToRoute ?: ‘verification.notice’)): 对于 Web 请求,将用户重定向到邮件验证通知页面。verification.notice 是 Laravel 默认的验证通知路由名称。
注册中间件
接下来,需要在 app/Http/Kernel.php 文件中注册这个新的中间件。将其添加到 $routeMiddleware 数组中,以便可以通过一个简短的键名来引用它:
// app/Http/Kernel.php
protected array $routeMiddleware = [
// ... 其他中间件
'verified-or-guest' => /App/Http/Middleware/EnsureEmailIsVerifiedUnlessGuest::class,
];
这里我们将其命名为 verified-or-guest,你可以根据偏好选择其他名称。
在路由中使用中间件
现在,你可以在任何需要此行为的路由或路由组上使用这个新的中间件了。例如,如果你希望整个应用程序都遵循这个逻辑,可以将其应用到 web 中间件组中,或者在 RouteServiceProvider 中定义一个全局的中间件组。更常见且灵活的做法是将其应用到特定的路由组或单个路由上:
// routes/web.php
use Illuminate/Support/Facades/Route;
Route::middleware(['web', 'verified-or-guest'])->group(function () {
Route::get('/', function () {
return view('welcome');
});
Route::get('/posts/{id}', function ($id) {
return "Post " . $id;
});
// ... 其他需要此验证逻辑的路由
});
// 如果只有部分路由需要,也可以单独应用
Route::get('/dashboard', function () {
// 只有已验证的用户才能访问此页面
return view('dashboard');
})->middleware(['auth', 'verified-or-guest']);
通过这种方式,当访客访问 / 或 /posts/1 时,中间件会检测到没有认证用户,从而允许请求继续。而当一个已登录但未验证邮箱的用户访问这些页面时,他们将被重定向到邮件验证通知页面。
注意事项
-
用户模型实现 MustVerifyEmail: 确保你的 App/Models/User 模型实现了 Illuminate/Contracts/Auth/MustVerifyEmail 接口,并且使用了 Illuminate/Auth/MustVerifyEmail trait。Laravel Breeze 或 Jetstream 通常会自动配置这些。
// app/Models/User.php use Illuminate/Contracts/Auth/MustVerifyEmail; use Illuminate/Foundation/Auth/User as Authenticatable; use Illuminate/Notifications/Notifiable; use Laravel/Sanctum/HasApiTokens; // 如果使用 Sanctum class User extends Authenticatable implements MustVerifyEmail { use HasApiTokens, Notifiable, MustVerifyEmail; // 确保包含 MustVerifyEmail trait // ... }登录后复制 -
邮件验证路由: 确保你的应用程序中定义了邮件验证相关的路由(例如 verification.notice、verification.verify 等)。Laravel UI、Breeze 或 Jetstream 通常会通过 Auth::routes([‘verify’ => true]); 或类似方式自动注册这些路由。
-
用户体验: 考虑为用户提供清晰的提示信息,引导他们完成邮件验证过程,例如在重定向页面上提供重新发送验证邮件的链接。
-
API 路由: 对于 API 路由,当用户未验证时,返回 403 状态码和相应的错误信息是标准做法,客户端应用应据此处理。
总结
通过创建 EnsureEmailIsVerifiedUnlessGuest 自定义中间件,我们成功地在 Laravel 中实现了一种灵活的邮件验证策略。这使得应用程序能够兼顾访客的无障碍访问体验,同时强制所有已登录用户完成邮箱验证,从而增强了用户账户的安全性。这种方法避免了默认 verified 中间件的局限性,提供了一个既安全又用户友好的解决方案。
以上就是Laravel 灵活实现可选邮件验证:访客自由,登录用户强制验证的详细内容,更多请关注php中文网其它相关文章!


