Laravel API Token 认证需同时满足三条件:auth:sanctum 中间件生效、createToken() 返回 plainTextToken、请求头严格为 Authorization: Bearer xxx,缺一则 Auth::user() 为 null。

直接说结论:Laravel 里 API Token 不是“生成一个字符串存数据库”就完事,关键在 auth:sanctum 中间件是否生效、createToken() 返回的是否是 plainTextToken、以及请求头是否严格为 Authorization: Bearer xxx —— 三者缺一不可,否则 Auth::user() 必然为 null。
为什么 Auth::user() 在 API 路由里总是 null
这不是代码写错了,而是认证链断在了中间某环:
-
apiguard 没配成sanctum(config/auth.php中'guards' => ['api' => ['driver' => 'sanctum']]) - 路由没加
auth:sanctum中间件,或错用了auth:api(旧 token 驱动) - 请求头写成
Authorization: Bearer xxx但实际发的是authorization: bearer xxx(Laravel 默认只认首字母大写的Authorization,且大小写敏感) - 前端用
fetch或axios发请求时没设credentials: 'include'(仅对 Cookie 场景),但当前是 Bearer Token,根本不需要它 —— 加了反而可能触发预检失败
login 接口返回 token 的正确姿势
别直接 return $token,也别 json_encode($token) —— $user->createToken() 返回的是 PersonalAccessToken 实例,含敏感字段(如哈希值 token),必须取 plainTextToken:
<pre class="brush:php;toolbar:false;">public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (!Auth::attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$user = Auth::user();
$token = $user->createToken('api-token'); // ← 这是实例,不是字符串
return response()->json([
'token' => $token->plainTextToken, // ← 只有这个能用
'user' => $user
]);
}
token 验证失败的典型报错和对应检查点
遇到 Unauthenticated 或空用户,按顺序快速排查:
-
Token has no user:数据库personal_access_tokens表里该 token 对应的tokenable_id找不到用户,常见于手动删过用户但没清 token 表 -
Call to undefined method Illuminate\Auth\RequestGuard::login():你在控制器里调了Auth::login($user),但apiguard 是无状态的,不支持login()方法 - 响应 401 但日志里没报错:检查中间件注册顺序 ——
auth:sanctum必须在throttle:api之前,否则限流中间件会先拦截未认证请求 - Postman 测试正常,APP 总失败:确认 APP 发的 header 是
Authorization(不是authorization),且值是Bearer xxx(Bearer后有一个空格)
token 过期与刷新要不要自己管
Sanctum 默认不设过期时间,token 一直有效,直到手动 $user->tokens()->delete() 或调用 $token->delete()。如果你需要时效控制:
- 不要改
config/sanctum.php里的expiration(它只对 Cookie 生效,对 Bearer Token 无效) - 自己在登录时加逻辑:
$token = $user->createToken('api-token', ['*'], now()->addHour(2)),第三个参数是expiresAt时间戳(注意:只有 Laravel 10.30+ 支持) - 更稳妥的做法是:业务层记录 token 创建时间,在中间件里手动校验
$request->user()->currentAccessToken->created_at是否超时
最易被忽略的一点:Sanctum 的 token 验证依赖数据库查询,如果 personal_access_tokens 表没建索引(尤其是 token 字段),高并发下会出现延迟甚至超时 —— 记得给 token 加唯一索引。


















