多守卫必须严格一一绑定guard与provider,所有调用点(登录、中间件、用户获取)均需显式指定守卫名,否则默认走web导致查错表、拿错用户;config/auth.php中每个guard的provider键须与providers数组中某键完全一致,且对应model必须真实存在并指向正确数据表。

多守卫不是“配完就能用”,而是必须保证 guard 和 provider 严格一一绑定,且所有调用点(登录、中间件、用户获取)都显式指定守卫名,否则默认走 web,查错表、拿错用户、登不出都是常态。
config/auth.php 里 guards 和 providers 怎么写才不串表
核心是“一对一定向绑定”:每个 guard 的 provider 键必须和 providers 数组里某个键完全一致,且该 provider 的 model 必须指向对应模型类。
-
'admin' => ['driver' => 'session', 'provider' => 'admins']—— guard 名为admin,它只认providers中叫admins的提供者 -
'admins' => ['driver' => 'eloquent', 'model' => App\Models\Admin::class]—— 这个model必须是真实存在的类,且该类的$table属性要匹配数据库表名(如没设,默认找admins表) - 别把
adminguard 的provider写成users,也别让adminsprovider 的model指向User::class,这两类错误直接导致Auth::guard('admin')->user()返回普通用户实例
Auth::guard('xxx')->attempt() 成功但 Auth::guard('xxx')->user() 为空
这不是密码错,是守卫和提供者没对齐的典型症状。重点检查三处:
-
Auth::guard('admin')->attempt($credentials)返回true,但后续Auth::guard('admin')->user()是null:确认adminsprovider 的model确实是App\Models\Admin::class,且该模型的$fillable包含email和password - 登录后
session里存的是User对象:说明守卫实际走的是web(默认),检查是否漏写了->guard('admin'),或中间件写成了auth而非auth:admin - 用了
remember参数仍无法保持登录:确认SESSION_DRIVER已在.env中设置(如redis或database),且StartSession中间件在Authenticate之前执行
路由中间件 auth:web,admin 是“或”逻辑,但 session 会互相覆盖
写成 middleware('auth:web,admin') 表示“任一守卫通过即可放行”,Laravel 会按顺序尝试 web、再 admin,短路生效。但它不解决底层冲突:
- 如果两个守卫都用
session驱动,且没隔离 session key(比如都用默认的login_web_59ba36ab),登录admin后,web的 session 就会被覆盖,反之亦然 - Sanctum 场景下更明显:默认
sanctumguard 只认usersprovider;要支持Admin模型,必须额外定义sanctum_adminguard 并绑定adminsprovider,不能复用sanctum - JWT 场景下,
tymon/jwt-auth默认所有 guard 共享黑名单 key,必须重写JWTBlacklist::add(),把$payload['guard']拼进 Redis key,否则Auth::guard('user')->logout()会误删admin的 token
最易被忽略的一点:所有调用点——登录、中间件、取用户、登出——都必须显式带 guard 名。漏掉一个,就退回 web,整个多守卫配置等于白配。











