
本文介绍如何在 laravel 中通过自定义中间件强制用户完成关键任务(如提交问卷)后才能访问受保护路由,避免依赖前端 javascript 或会话手动判断,确保逻辑安全、可复用且符合框架最佳实践。
本文介绍如何在 laravel 中通过自定义中间件强制用户完成关键任务(如提交问卷)后才能访问受保护路由,避免依赖前端 javascript 或会话手动判断,确保逻辑安全、可复用且符合框架最佳实践。
在 Laravel 应用中,常需实现“条件性路由准入”——例如:用户登录后必须先完成实名认证、新手引导或满意度问卷,方可访问后台主功能页。这类需求若仅靠前端跳转或 JS 判断,极易被绕过;而将校验逻辑分散在各控制器中又违背单一职责原则。最优雅、安全且符合 Laravel 设计哲学的方案是使用自定义中间件(Custom Middleware)。
✅ 正确实现步骤
1. 创建中间件
运行 Artisan 命令生成中间件类:
php artisan make:middleware RequireSurveySubmitted
编辑生成的 app/Http/Middleware/RequireSurveySubmitted.php,编写核心校验逻辑:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RequireSurveySubmitted
{
public function handle(Request $request, Closure $next)
{
// 确保用户已登录
if (!Auth::check()) {
return redirect()->route('login');
}
$user = Auth::user();
// 校验用户是否已提交问卷(假设模型中有 is_survey_submitted 字段)
// 或通过关联关系/查询判断,例如:
// $hasSubmitted = $user->surveys()->where('status', 'completed')->exists();
if (!$user->is_survey_submitted) {
return redirect()->route('survey.index')
->with('warning', '请先完成新手问卷,以便我们为您提供更优质的服务。');
}
return $next($request);
}
}⚠️ 注意:示例中 is_survey_submitted 是用户模型的布尔属性(可来自数据库字段、缓存或 Eloquent 访问器)。实际项目中建议使用更健壮的查询逻辑(如检查最新有效问卷记录),避免因字段未同步导致误判。
2. 注册中间件(Laravel 10+ 可选)
若使用 Laravel 10 或更高版本,中间件默认自动发现;否则需在 app/Http/Kernel.php 的 $routeMiddleware 数组中注册:
'can-submit' => \App\Http\Middleware\RequireSurveySubmitted::class,
3. 在路由中应用中间件
在 routes/web.php 中为受保护路由添加中间件:
// 允许访问的页面(如仪表盘、设置页等)
Route::middleware(['auth', 'can-submit'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
Route::get('/settings', [SettingsController::class, 'edit'])->name('settings.edit');
});
// 问卷相关路由应排除该中间件,确保用户能访问
Route::middleware('auth')->group(function () {
Route::get('/survey', [SurveyController::class, 'index'])->name('survey.index');
Route::post('/survey/submit', [SurveyController::class, 'submit'])->name('survey.submit');
});? 关键设计要点说明
- 服务端强校验:所有逻辑在中间件中执行,杜绝客户端篡改风险;
- 与认证中间件协同:务必前置 auth 中间件,确保 Auth::user() 可用;
- 用户体验友好:重定向至问卷页并携带提示信息,避免用户困惑;
- 可扩展性强:可轻松扩展为多任务检查(如 is_profile_complete && is_survey_submitted),或抽象为策略类(Policy)进一步解耦。
❌ 常见误区规避
- ✖️ 不要在前端用 JavaScript 隐藏/禁用链接——这仅是体验优化,无法阻止直接访问 URL;
- ✖️ 避免在每个控制器方法开头重复写 if (!auth()->user()->hasCompletedSurvey()) { ... }——违反 DRY 原则;
- ✖️ 不要仅依赖 Session 标记(如 session('survey_submitted'))——Session 易被伪造或过期,应以持久化数据源(如数据库)为准。
通过以上方式,你不仅实现了安全可靠的访问控制,还构建了一个可复用于其他“前置任务”场景(如协议签署、邮箱验证)的通用中间件骨架。这是 Laravel 开发者掌握权限与流程管控能力的重要一步。











