Sanctum 的 tokenable_type 和 tokenable_id 不能直接实现单点登录,因其默认允许多设备共存;需在登录时调用 $user->tokens()->delete() 清空旧 token,并配合前端清除本地存储及拦截 401 响应。
为什么 Sanctum 的 tokenable_type 和 tokenable_id 不能直接用来做单点登录
Sanctum 默认不阻止同一用户多设备登录,因为它的数据库表 personal_access_tokens 只记录 token 元信息,不标记“当前有效会话数”或“是否被踢出”。你删掉某条 token,只影响那个 token,其他同用户的 token 照常可用——这不是单点登录,是“多点共存”。要实现单点登录,必须主动干预 token 的生成和校验逻辑。
如何在登录时自动失效旧 token(关键步骤)
核心是在用户成功认证后、返回新 token 前,清空该用户所有已有 Sanctum token。注意:不是删 users 表数据,而是删 personal_access_tokens 中对应 tokenable_id 和 tokenable_type 的记录。
- 使用
$user->tokens()->delete()—— 这是最安全的方式,它走 Eloquent 关系,自动匹配tokenable_id和tokenable_type = 'App\Models\User' - 别用
DB::table('personal_access_tokens')->where(...)->delete(),容易漏掉tokenable_type判断,跨模型时出错 - 确保你的 User 模型已 use
Laravel\Sanctum\HasApiTokens,否则tokens()关系不存在
示例片段(在登录控制器中):
$user = Auth::user();
$user->tokens()->delete(); // ⚠️ 此行必须在 createToken() 之前
$token = $user->createToken('api-token')->plainTextToken;
怎么让已发出的旧 token 立即失效(不只是删库)
删 token 记录只是第一步。如果旧 token 已被客户端缓存并仍在请求头中使用,Sanctum 默认仍会通过 Guard::user() 找到对应用户(因为 token hash 还没被校验前就查库失败了?不,实际是:token 存在才校验;删了就 401)。但要注意两个边界情况: