Sanctum 默认不校验 X-Sanctum-Token,因其 API token 认证依赖数据库中 tokenable_type、tokenable_id 和 abilities 字段比对,而非该请求头;该 header 仅为 Jetstream 或前端 SDK 封装别名,后端原生不识别。

Sanctum 为什么默认不校验 X-Sanctum-Token?
因为 Sanctum 的 API token 认证模式默认走的是 tokenable_type + tokenable_id + abilities 数据库比对,不是靠请求头里的 X-Sanctum-Token 做无状态校验——这个 header 实际上是 Laravel Jetstream 或自定义前端 SDK 用的,原生 Sanctum 的 EnsureFrontendRequestsAreStateful 中间件根本不读它。
常见错误现象:401 Unauthorized,但 token 明明存在、数据库里也查得到;或者 Postman 里手动加了 X-Sanctum-Token 却完全没效果。
- API 路由必须用
sanctum中间件(不是auth:sanctum),且该中间件只对带 session 的请求生效(比如 SPA 同域) - 纯 API 场景(如移动端、第三方调用)必须用
auth:sanctum+Token请求头(格式:Bearer {token}) -
X-Sanctum-Token是前端 SDK 封装的别名,后端不识别;硬要用就得自己写中间件解析并调用Sanctum::authenticateToken()
怎么让 Sanctum 支持多模型(比如 Admin 和 User)?
Sanctum 默认只支持 User 模型,因为 HasApiTokens trait 里写死了 BelongsTo 关系指向 App\Models\User。强行换模型会导致 tokenable_id 找错记录,或 tokenable_type 写成字符串却查不到对应类。
使用场景:后台管理员 API 和用户 API 共用一套 token 表,但需要隔离权限和生命周期。
- 在
config/auth.php的guards下新增adminguard,driver 设为sanctum,provider 指向admins - 创建
Admin模型,实现Authenticatable接口,并添加HasApiTokenstrait - 重写
Sanctum::$personalAccessTokenModel(Laravel 9.2+)或继承PersonalAccessToken类,覆盖tokenableType()方法返回正确模型名 - 注意 migration 中
tokenable_type字段长度要够(默认 191 不够全路径),建议改成255
Sanctum::user() 返回 null,但 Auth::user() 有值?
这是最常被忽略的中间件顺序问题。Sanctum::user() 依赖 SanctumServiceProvider 注册的 AuthenticateSession 和 EnsureFrontendRequestsAreStateful,而这两个中间件必须在 StartSession 之后、ShareErrorsFromSession 之前运行。
性能影响:如果中间件顺序错,每次请求都会跳过 Sanctum 的 session 解析逻辑,导致 token 无法绑定到当前会话。
- 检查
app/Http/Kernel.php中$middlewareGroups['api']是否漏掉了EnsureFrontendRequestsAreStateful::class - 确认
$middlewareGroups['web']包含EncryptCookies、AddQueuedCookiesToResponse、StartSession—— 缺一不可 - 不要在
api路由组里用auth:sanctum处理 web 请求,反之亦然;两者中间件栈完全不同
CSRF token mismatch 报错时,Sanctum 还能用吗?
能,但只限于 API token 模式。CSRF 错误只影响基于 session 的鉴权流程(即 EnsureFrontendRequestsAreStateful 分支),跟 Bearer {token} 方式完全无关。
容易踩的坑:本地开发用 http://localhost:3000 调后端 http://localhost:8000,跨域触发了 CSRF 校验,但前端又没发 X-XSRF-TOKEN,于是整个 Sanctum session 流程中断,连带 Sanctum::currentAccessToken() 也返回 null。
- 开发时把前端域名加进
SESSION_DOMAIN(如.localhost)并启用SameSite=None; Secure(需 HTTPS) - 更简单做法:API 路由全部走
auth:sanctum+ Bearer token,绕开 session 和 CSRF - 确保
VerifyCsrfToken中间件没有被意外禁用或跳过关键路由
复杂点在于:同一个项目里混合用了 session 鉴权和 token 鉴权,但共享了 sanctum 中间件配置,稍不注意就会互相干扰。这时候得拆开中间件组,而不是指望一个配置打天下。


















