
本文详解 laravel 9 + sanctum 前后端分离场景下登出失败(401 unauthorized)的根本原因,并提供符合官方规范、安全可靠的登出实现方案,涵盖后端逻辑修正、前端请求优化及中间件配置要点。
本文详解 laravel 9 + sanctum 前后端分离场景下登出失败(401 unauthorized)的根本原因,并提供符合官方规范、安全可靠的登出实现方案,涵盖后端逻辑修正、前端请求优化及中间件配置要点。
在使用 Laravel 9 配合 Sanctum 构建 SPA(如 React 前端)时,常见错误是:登录成功后能正常访问 /api/user,但调用 /api/logout 却返回 401 Unauthenticated。问题根源往往不在 CORS 或 Token 传递本身,而在于登出逻辑违背了 Sanctum 的认证模型。
❌ 错误写法分析:为什么你的 logout() 报 401?
你当前的控制器方法存在两个关键问题:
public function logout(Request $request){
Auth::attempt([ // ← 错误起点!
'email'=>$request->email,
'password'=>$request->password
]);
Auth::user()->token()->delete(); // ← 此行执行前 Auth::user() 已为 null
return response(['message'=>'Successfully Logging out']);
}-
Auth::attempt()是用于 登录认证 的方法,它需要明文密码并触发 session 创建/验证,完全不适用于登出场景; - 在受
auth:sanctum中间件保护的路由中,Sanctum 已通过 Bearer Token 自动将当前用户注入Auth::user();你却额外调用Auth::attempt(),这不仅冗余,更会因$request->email/password为空导致认证失败,进而使后续Auth::user()返回null,最终抛出401。
✅ 正确登出的核心原则:信任 Sanctum 的中间件已完成认证,直接操作当前用户的 Personal Access Token 即可。
✅ 正确实现:简洁、安全、符合 Sanctum 规范
1. 后端控制器修正(AuthController.php)
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
public function logout(Request $request)
{
// ✅ Sanctum 会自动解析 Bearer Token 并设置 Auth::user()
$user = Auth::user();
// ✅ 删除当前用户的 Personal Access Token(即本次会话 Token)
$user->currentAccessToken()->delete();
// ✅ 清除前端 Cookie(可选,取决于是否使用 stateful 模式)
// 如果你启用了 stateful 认证(如 `SANCTUM_STATEFUL_DOMAINS`),建议同时清除 session
// Auth::guard('web')->logout();
return response()->json([
'message' => 'Successfully logged out'
]);
}? 关键点:
- 移除所有
Auth::attempt()、$request->email/password相关逻辑;- 使用
$user->currentAccessToken()->delete()精准删除当前请求所用的 Token(非全部 Token);- 若需彻底退出 stateful 会话(如同时使用 Web Guard),可追加
Auth::guard('web')->logout()。
2. 前端登出请求优化(Dropdown.js)
你当前的 Axios 请求存在格式错误:headers 被错误地放在请求体(第二个参数)中,而非配置对象内。
✅ 修正后的登出请求:
function logout() {
axios
.post('http://backend.bisa_js.test/api/logout', {}, { // ← 空数据体,配置对象放第三位
headers: {
Accept: 'application/json',
Authorization: `Bearer ${cookie.token}`,
},
withCredentials: true, // ✅ 必须启用,确保 Cookie(如 XSRF-TOKEN)被发送
})
.then((response) => {
console.log(response.data.message);
// 清理前端存储
removeCookie('token', { path: '/' });
removeCookie('user', { path: '/' });
navigate('/login');
})
.catch((error) => {
console.error('Logout failed:', error.response?.data || error.message);
// 即使 API 失败,也应清理本地凭证
removeCookie('token', { path: '/' });
removeCookie('user', { path: '/' });
navigate('/login');
});
}⚠️ 注意事项:
withCredentials: true是必须项,否则浏览器不会发送XSRF-TOKENCookie,导致 CSRF 验证失败(尤其在EnsureFrontendRequestsAreStateful中间件下);- 登出请求体应为空
{},Headers 必须置于 Axios 配置对象(第三个参数)中;- 建议无论后端是否成功,前端都主动清除
token和userCookie,保障状态一致性。
3. 配置复查(关键!)
确保以下配置与 Sanctum 官方要求严格一致:
config/sanctum.phpstateful域名必须包含你的前端地址(如localhost:3000),且guard应为['web'](你已正确配置)。config/cors.phpsupports_credentials必须为true,allowed_origins需明确列出前端域名(你已做到)。app/Http/Kernel.phpapi中间件组中EnsureFrontendRequestsAreStateful::class必须位于throttle之前(你当前顺序正确)。-
CSRF 保护(重要补充)
Sanctum 登出需校验 CSRF Token。请确保前端在登出前已预加载 CSRF Cookie:// 在登出前或 App 初始化时调用 await axios.get('http://backend.bisa_js.test/sanctum/csrf-cookie');或在
Login.js中取消注释该行并确保执行。
? 总结:登出成功的三大支柱
| 组件 | 要求 | 检查点 |
|---|---|---|
| 后端逻辑 | 不依赖密码,仅操作 currentAccessToken()
|
✅ 移除 Auth::attempt(),使用 $user->currentAccessToken()->delete()
|
| 前端请求 | 正确携带 Bearer Token + withCredentials: true
|
✅ Headers 在配置对象中,空请求体,预加载 CSRF Cookie |
| 中间件配置 |
EnsureFrontendRequestsAreStateful 生效且顺序正确 |
✅ api 中间件组首位,stateful 域名匹配,CORS 支持凭据 |
遵循以上步骤,你的 Laravel 9 Sanctum 登出功能将稳定可靠,彻底解决 401 Unauthenticated 问题。


















