Laravel多guards是应对多身份业务的必需配置,非可选功能;需在config/auth.php中严格一一对应定义guards与providers,确保driver、model、provider键值精准匹配,避免session冲突、模型误查等硬伤。

直接说结论:Laravel 的多 guards 不是“可选功能”,而是应对真实业务分层的必需配置;只要你的应用存在 ≥2 种用户身份(比如前台用户、后台管理员、API 客户端、商户),就必须拆开定义独立的 guard 和 provider,否则会踩 session 冲突、模型误查、token 混用等硬伤。
怎么在 config/auth.php 里正确定义多个 guards
核心是两步:先配 guards,再配对应的 providers,二者必须一一对应,且 provider 名要和 guard 里的 provider 键值完全一致。
-
guards中每个守卫必须指定driver(如session、sanctum、http-basic)和provider(字符串名,不写模型路径) -
providers中每个提供者必须指定driver(通常为eloquent)和model(完整类名,如App\Models\Admin) - 别把
api守卫的provider指向users,却让admin守卫也指向users——这会导致管理员登录后Auth::guard('admin')->user()返回普通用户实例 - 如果你用
sanctum做 API 认证,它默认只认users提供者;要支持多模型,必须额外配一个sanctum_admin守卫并绑定admins提供者
为什么 Auth::guard('xxx')->attempt() 有时返回 true 却拿不到用户
这不是代码 bug,而是守卫和提供者没对齐的典型表现。常见于以下情况:
- 调用
Auth::guard('admin')->attempt($credentials)后,Auth::guard('admin')->user()为null:检查adminguard 的provider是否指向了正确的Admin模型,且该模型的$fillable包含email和password - 认证成功但 session 里存的是
User模型:确认adminprovider 的model是App\Models\Admin::class,不是App\Models\User::class - 使用
remember参数后仍无法保持登录:session驱动的守卫依赖 Laravel 的 session 存储机制,确保SESSION_DRIVER环境变量已设(如redis或database),且中间件顺序中StartSession在Authenticate之前
路由中 auth:web,admin 是“或”还是“与”逻辑
逗号分隔的多个守卫名(如 auth:web,admin)是明确的“或”逻辑:Laravel 会按顺序尝试每个守卫,只要其中一个成功,请求就放行。
- 它不是同时校验两个守卫,也不是合并权限——只是短路式尝试
- 这个特性常用于开放接口:允许用户用 cookie 登录(
web),也允许管理员用 token 直接访问(admin) - 注意:如果两个守卫都用了
session驱动,且共享同一个 session key(如都用login_web_59ba36ab...),会出现互相覆盖;务必为不同守卫设置独立的session配置项(如session→store或自定义id) - 不要在同一个路由上混用
session和sanctum守卫却不处理跨域或 CSRF,否则前端带 Cookie 请求可能被sanctum拒绝,而sanctumtoken 又被session守卫忽略
动态切换 guard 时最容易漏掉的校验点
用 Auth::guard($request->guard)->attempt(...) 实现统一登录接口时,最危险的不是逻辑,而是边界失控。
- 必须用
in:规则白名单限制guard参数值,禁止传入未定义的守卫名(如guard=foo会导致Auth::guard('foo')返回 null,后续调用attempt()报Call to a member function attempt() on null) - 不同守卫的密码加密方式可能不同(
User用 bcrypt,Admin用 argon2),但attempt()不会自动适配——确保所有模型都用相同哈希算法,或在登录前手动比对 - 若某守卫用
token驱动(如旧版api),attempt()成功后不会自动创建 token,需显式调用$user->createToken(...);而sanctum守卫的attempt()本身不生成 token,得靠后续$user->createToken() - 别在控制器里硬编码
Auth::guard('admin')多次——抽成私有方法或 service,并把 guard 名作为参数注入,方便测试和 mock
多守卫真正的复杂点不在配置,而在状态隔离:session、cookie、token、CSRF token、remember me cookie,这些全都绑定在守卫名上。一旦命名或驱动错位,问题会延迟暴露——比如登录成功但登出失败,或用户能进后台却看不到自己的头像。动手前,先画一张 guard ↔ provider ↔ model ↔ driver 的映射表,比写十行代码更管用。


















