控制器中不应放置权限判断逻辑,而应由中间件统一处理认证、角色验证等横切关注点,以避免重复代码、绕过校验和测试困难;中间件只负责拦截或放行请求,不参与业务数据组装或响应生成。

控制器里不该放权限判断逻辑
权限校验、登录态检查、角色验证这些事,Controller 方法里不应该写 if (!Auth::check()) 或 if (!$user->hasRole('admin'))。这不是控制器的职责,而是中间件该干的活。一旦写进控制器,会导致:重复代码(每个方法开头都加一遍)、绕过校验(比如直接调用方法不走路由)、测试困难(要 mock 掉整个认证流程)。Laravel 的请求生命周期明确把中间件放在控制器之前执行,就是为了解耦这类横切关注点。
中间件不处理业务数据组装
中间件里别做 User::with('posts')->find($id)、别调用 OrderService::calculateTotal()、也别返回视图或 JSON 响应体。它的任务是「拦」或「放」,不是「算」或「构」。常见错误包括:在中间件里查数据库并存到 $request->attributes 传给控制器——这看似省事,实则模糊了责任边界,让中间件承担了数据准备职责,后续调试时很难判断数据来源是中间件注入的还是控制器自己查的。真正需要预加载的数据,应该由控制器自己按需处理,或通过 Laravel 的路由模型绑定(Route::get('/user/{user}', ...))自动解析。
哪些逻辑适合放在中间件里
以下场景用中间件最自然:
- 统一校验请求头是否含有效
Authorizationtoken(auth:sanctum) - 拦截未验证邮箱的用户访问敏感页面(
verified) - 限制 API 请求频率(
throttle:60,1) - 根据 URL 路径自动设置语言 locale(
SetLocale) - 记录所有入站请求日志(
LogRequest)
关键判断标准:这个逻辑是否适用于「一批路由」?是否与具体业务动作无关?如果是,就该抽成中间件;如果只服务于某个控制器方法的特定分支,那就留在控制器里用条件判断更清晰。
复杂权限场景下中间件和控制器怎么协作
比如「用户只能编辑自己创建的文章」,这不是简单角色判断,而是带数据上下文的授权。这时候:
- 中间件负责基础准入(
auth),确保已登录 - 控制器内使用
authorize()方法或 Policy(如$this->authorize('update', $post))做细粒度检查 - Policy 类里才真正执行
$post->user_id === $user->id这类逻辑
强行把这种带模型实例的判断塞进中间件,会迫使中间件去解析路由参数、查询模型、甚至引入 Eloquent 依赖——它本不该知道 Post 模型长什么样。边界一旦被打破,后续加缓存、改权限规则、做单元测试都会变重。











