最规范的方式是路由或控制器层面不声明中间件:路由中不调用->middleware('auth'),控制器中用$this->middleware('auth')->except(['index', 'show'])排除指定方法。

在 Laravel 8.x 中,若想对某些路由或控制器方法跳过中间件(尤其是自带的 auth、verified 或自定义中间件),不能靠“在中间件里写 if 判断跳过”,而应从**注册/应用层面**控制——即让中间件不作用于目标路由。以下是几种常用且规范的方式:
方式一:路由定义时排除中间件(推荐)
使用 except 方法(仅适用于全局中间件组,如 web 或 api 组中已分配的中间件)不适用;真正有效的是在路由分组或单个路由上,**不绑定该中间件**。
例如,跳过 auth 验证:
// ✅ 正确:登录页不需要 auth 中间件
Route::get('/login', [LoginController::class, 'showLoginForm'])->name('login');
// ❌ 错误:不要这样写(auth 会执行并重定向)
Route::get('/login', [LoginController::class, 'showLoginForm'])->middleware('auth')->name('login');
如果你用的是中间件组(如 web),默认已包含 EncryptCookies、StartSession 等,但 auth 并不在其中——它是你手动加的。所以只需确保「不需要验证的路由」不调用 ->middleware('auth') 即可。
方式二:在控制器构造函数中排除中间件
适用于控制器级别批量跳过。Laravel 8.x 支持在控制器构造函数中用 except() 排除指定方法:
class PostController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
}
这样,index 和 show 方法就不会经过 auth 中间件。注意:except 只对当前中间件生效,且方法名必须与控制器中实际定义的一致。
方式三:自定义中间件中动态跳过(慎用)
如果你开发的是自定义中间件(比如权限检查),可以在中间件逻辑中判断是否放行:
public function handle($request, Closure $next)
{
// 跳过 CLI、测试环境、或特定路由
if ($request->is('api/public/*') || app()->runningInConsole() || $request->routeIs('health')) {
return $next($request);
}
// 执行你的验证逻辑……
if (! $request->user() || ! $request->user()->hasRole('admin')) {
abort(403);
}
return $next($request);
}
⚠️ 注意:不要在 auth 这类核心中间件里“强行跳过”,它由框架深度集成,修改易引发不可预知行为。动态跳过只建议用于你完全掌控的自定义中间件。
方式四:使用中间件参数做条件控制(进阶)
给中间件传参,在内部决定是否执行验证逻辑:
// 路由中
Route::get('/dashboard', [DashboardController::class, 'index'])
->middleware('role:admin,skip-if-guest');
// 中间件内
if (in_array('skip-if-guest', $parameters) && ! $request->user()) {
return $next($request);
}
需自行在中间件 handle 方法中解析 $parameters,适合需要灵活策略的场景,但会增加维护成本,非必要不建议。
核心原则:Laravel 的中间件是“声明式”的,跳过 = 不声明,而不是在执行时绕过。优先用路由定义或控制器构造函数控制,清晰、安全、符合框架设计思想。


















