Laravel中间件怎么写 Laravel如何限制访问权限 【必看】

1次阅读

必须用 php artisan make:middleware 创建中间件类,否则即使文件存在且命名规范,laravel 也不会识别;生成的类需保留 handle($request, closure $next) 签名,命名空间与 psr-4 严格匹配。

Laravel中间件怎么写 Laravel如何限制访问权限 【必看】

中间件类怎么创建才不会被 Laravel 忽略

Laravel 不会自动加载你随手新建的 PHP 文件,中间件必须通过 php artisan make:middleware 创建,否则即使类存在、命名规范,app/http/Middleware/ 下也不会被框架识别。

常见错误现象:写完类、在 Kernel.php 里注册了,但请求完全不进中间件——八成是没用 Artisan 命令生成,导致缺少 handle 方法签名或命名空间错位。

  • 必须用 php artisan make:middleware CheckAdminRole,不要手动新建文件
  • 生成的类默认有 public function handle($request, Closure $next),别删掉 Closure $next 参数,否则 $next($request) 会报错
  • 类名要符合 PSR-4,比如 CheckAdminRole 对应文件名 CheckAdminRole.php,不能写成 checkadminrole.phpcheck_admin_role.php

权限判断逻辑写在哪?别在 handle 里查数据库

中间件的 handle 方法执行频次极高,每次请求都走一遍。如果在里面调 Auth::user()->roles()->get() 这类 Eloquent 查询,接口延迟立刻翻倍,还容易触发 N+1。

正确做法是复用已加载的数据,比如 Laravel 自带的 auth guard 已经把用户实例和基础权限缓存在内存里,优先用 $request->user() + 预加载字段或缓存好的权限标识。

  • 查角色推荐用 $request->user()?->hasRole('admin')(需配合 spatie/laravel-permission 等扩展),而不是重新查库
  • 自定义权限如 “能编辑当前文章”,把 $post->user_id$request->user()->id 对比即可,别再查一次 Post::find()
  • 需要复杂判断时,提前在 AppServiceProviderboot 里绑定一个轻量服务,中间件里 app(MyPermissionChecker::class)->can(...)

路由组里注册中间件,为什么有些请求还是没拦截

最常漏掉的是中间件参数传递方式。比如想限制「只有拥有 post.edit 权限的人才能访问编辑页」,写成 middleware(['can:post.edit']) 是对的;但若写成 middleware('can:post.edit')(单引号没包数组),Laravel 会当字符串处理,直接忽略参数,变成无条件放行。

另外,can 中间件依赖 Laravel 的 Gate 机制,如果你没在 AuthServiceProvider@boot 里用 Gate::define('post.edit', ...) 定义规则,它永远返回 false,但不会报错,只会静默拒绝。

  • 带参数的中间件必须用数组语法:middleware(['can:post.update', 'throttle:30,1'])
  • can 中间件底层调 Gate::allows(),没定义对应规则就一律 deny,检查 app/Providers/AuthServiceProvider.phpboot 方法
  • 测试时别只测 GET,POST/PUT 请求可能因 csrf表单验证提前终止,根本到不了中间件层

中间件里 redirect() 后为什么页面空白或跳错

直接写 return redirect('/login') 没问题,但很多人会写 redirect()->route('login') 却忘了在 routes/web.php 里真有叫 login 的命名路由——结果抛出 Route

 此处含有隐藏内容,登录后即可查看!

not defined 错误,而这个异常在中间件里常被静默吞掉,只显示空白页。

更隐蔽的问题是重定向目标带参数时没做空值判断。比如 redirect()->route('post.show', ['post' => $post->id]),但 $post 是 NULL,就会触发 Null passed to route parameter

  • 所有 route() 调用前,先确认命名路由存在:php artisan route:list | grep login
  • 涉及模型 ID 的重定向,加一层存在性检查:if (!$post) { return redirect('/'); }
  • 想返回上一页,用 redirect()->back(),但注意它依赖浏览器 Referer 头,API 请求或某些代理环境下可能为空,建议 fallback 到固定路径

事情说清了就结束。权限控制真正难的不是写中间件,而是决定“谁在什么条件下能做什么”——这个逻辑一旦散落在中间件、Policy、Gate、前端按钮里,很快就会失控。

text=ZqhQzanResources