Laravel 12 Sanctum对接React SPA时认证接口返回401未授权问题
问题描述
在同顶级域名下使用Laravel 12的Sanctum组件对接React.js单页应用(SPA),登录、登出接口调用正常,XSRF-TOKEN已成功设置,但调用需认证的API接口时返回401未授权错误。
前端Axios配置
import axios from 'axios'; const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api/v1'; const VITE_TOKEN_STORAGE_KEY = import.meta.env.VITE_TOKEN_STORAGE_KEY || 'bricoloman_token'; const SANCTUM_BASE_URL = import.meta.env.SANCTUM_BASE_URL || 'http://localhost:8000'; // Base configuration for Axios instance const api = axios.create({ baseURL: API_BASE_URL, withCredentials: true, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, }); const sanctumApi = axios.create({ baseURL: SANCTUM_BASE_URL, withCredentials: true, }); api.interceptors.request.use(config => { const token = localStorage.getItem(VITE_TOKEN_STORAGE_KEY); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); api.interceptors.response.use( response => response, error => { return Promise.reject(error); } ); export const getCsrf = async () => { await sanctumApi.get('/sanctum/csrf-cookie'); };
后端配置
.env配置
SANCTUM_STATEFUL_DOMAINS=localhost:3000 SESSION_DOMAIN=localhost SESSION_DRIVER=cookie SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ APP_URL=http://localhost
sanctum.php配置
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:8000,localhost:8080,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '', Sanctum::currentApplicationUrlWithPort() ))),
cors.php配置
return [ 'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout', 'register'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000', env('APP_URL')], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => ['Authorization'], 'max_age' => 0, 'supports_credentials' => true, ];
api.php路由配置
<?php use App\Http\Controllers\Api\V1\AuthController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::prefix('v1')->group(function () { Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']); Route::middleware('auth:sanctum')->group(function () { Route::get('/user', function (Request $request) { return $request->user(); }); Route::post('/logout', [AuthController::class, 'logout']); }); });
已尝试的解决措施
- 确保Axios中设置了
withCredentials: true - 验证登录前已调用
/sanctum/csrf-cookie处理CSRF防护 - 检查后续请求中已携带Authorization Bearer令牌
- 确认前后端
SESSION_DOMAIN和SANCTUM_STATEFUL_DOMAINS配置一致
进一步排查建议
验证令牌存储与携带正确性
- 登录成功后打印
localStorage.getItem('bricoloman_token'),确认令牌与后端登录接口返回的plainTextToken完全一致; - 在浏览器Network面板查看需认证接口的请求头,确认
Authorization: Bearer [token]存在且令牌无拼写错误。
- 登录成功后打印
检查后端登录接口逻辑
- 确保登录接口返回的是用户创建的Sanctum令牌:
return response()->json([ 'token' => $user->createToken('auth_token')->plainTextToken, 'user' => $user ]); - 避免返回数据库中存储的哈希令牌,必须使用
plainTextToken。
- 确保登录接口返回的是用户创建的Sanctum令牌:
调整SESSION_DOMAIN配置
- 本地开发时尝试将
SESSION_DOMAIN改为.localhost(注意前缀的点),确保跨端口的cookie共享生效; - 重启Laravel服务使配置生效。
- 本地开发时尝试将
查看Laravel日志
- 打开
storage/logs/laravel.log,查找401错误对应的详细日志,通常会提示令牌无效、用户未找到等具体原因。
- 打开
临时放宽CORS配置测试
- 将
cors.php中的allowed_origins改为['*'],测试是否为跨域配置问题(生产环境请勿保留此设置)。
- 将
清除浏览器缓存与Cookie
- 清除浏览器中
localhost相关的所有Cookie和缓存,重新登录后再调用认证接口。
- 清除浏览器中
内容的提问来源于stack exchange,提问作者AZNIDI
相关产品推荐
相关产品推荐

