
本文介绍如何在 laravel 中通过自定义中间件强制用户完成特定任务(如提交问卷)后,方可访问其他路由,确保业务流程合规性与用户体验一致性。
本文介绍如何在 laravel 中通过自定义中间件强制用户完成特定任务(如提交问卷)后,方可访问其他路由,确保业务流程合规性与用户体验一致性。
在 Laravel 应用中,常需保障关键业务流程的线性执行——例如:新用户登录后必须先填写初始问卷,才能浏览仪表盘或使用核心功能。这种“前置任务强制完成”逻辑不应依赖前端 JavaScript(易被绕过),也不宜散落在各控制器中重复校验。最安全、可复用且符合 Laravel 架构思想的方案是自定义中间件(Middleware)。
✅ 正确实现方式:基于用户状态的中间件校验
中间件在请求进入控制器前执行,天然适合做全局访问守门人。以下是一个生产就绪的 EnsureSurveyCompleted 中间件示例:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class EnsureSurveyCompleted
{
public function handle(Request $request, Closure $next)
{
// 仅对已认证用户生效
if (!Auth::check()) {
return redirect()->route('login');
}
$user = Auth::user();
// 核心逻辑:检查用户是否已提交问卷
// 假设 User 模型有一个布尔字段 `survey_submitted`
if (!$user->survey_submitted) {
// 重定向至问卷页,并附带提示信息
return redirect()
->route('survey.index')
->with('warning', '请先完成初始问卷,以解锁全部功能。');
}
return $next($request);
}
}? 关键说明:
- 使用 Auth::user() 获取当前用户,避免依赖 $request 的不可靠属性(如原答案中的 $request->survey_submitted 并不存在);
- 通过模型字段(如 survey_submitted)或关联关系(如 !$user->survey()->exists())判断任务完成状态,确保数据一致性;
- 提供友好的重定向与提示,提升用户体验。
? 注册并应用中间件
-
注册中间件(app/Http/Kernel.php):
将其加入 $routeMiddleware 数组:protected $routeMiddleware = [ // ... 'survey.completed' => \App\Http\Middleware\EnsureSurveyCompleted::class, ]; -
在路由中启用(routes/web.php):
// 全局保护:所有需授权的路由组 Route::middleware(['auth', 'survey.completed'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard'); Route::get('/settings', [SettingsController::class, 'edit'])->name('settings.edit'); // ... 其他受保护路由 }); // 或单独为某条路由启用 Route::get('/premium/features', [FeatureController::class, 'show']) ->middleware('survey.completed') ->name('features.premium');
⚠️ 注意事项与最佳实践
-
数据库字段建议:在 users 表中添加 survey_submitted 布尔字段(默认 false),并在问卷提交成功后原子化更新:
Auth::user()->update(['survey_submitted' => true]);
- 避免缓存干扰:若使用响应缓存(如 laravel-responsecache),需排除受保护路由,防止未完成用户缓存了已授权页面。
-
API 场景适配:对于 API 路由,应返回 403 Forbidden 状态码及 JSON 错误提示,而非重定向:
if (!$user->survey_submitted) { return response()->json([ 'message' => 'Survey not completed. Access denied.' ], 403); } - 扩展性考虑:可将“任务类型”参数化,使中间件支持多种前置任务(如 profile_completed、tos_accepted),提升复用性。
通过此方案,你不仅实现了安全可靠的访问控制,还遵循了 Laravel 的约定优于配置原则,代码清晰、易于测试与维护。真正的权限治理,始于一次严谨的中间件拦截。










