Laravel Sanctum跨域认证失败:请求/user接口返回Unauthorized
Laravel Sanctum跨域授权失败排查与解决
问题场景
API部署地址:https://example.com,Vue.js应用部署地址:https://app.example.com,二者均为HTTPS域名。
已完成以下配置:
.env配置:
SESSION_DOMAIN=.example.com SANCTUM_STATEFUL_DOMAINS=https://app.example.com
- Axios配置:
import axios from 'axios' const server = axios.create({ baseURL: 'https://example.com' }) server.defaults.withCredentials = true server.defaults.withXSRFToken = true
- 曾在
sanctum.php中设置guard为api:
'guard' => ['api']
kernel.php的api中间件组配置:
'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ],
- 全局
$middleware组中添加:
\Illuminate\Session\Middleware\StartSession::class,
应用流程:点击登录按钮后,先请求/sanctum/csrf-cookie返回204并设置Cookie;接着登录请求也返回204,但请求受保护的/user接口(路由配置如下)时返回unauthorized:
Route::middleware('auth:sanctum')->group(function () { Route::get('/user', [UserController::class, 'index']); });
Postman测试结果一致。
更新后的完整配置
config/sanctum.php
<?php use Laravel\Sanctum\Sanctum; return [ 'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', Sanctum::currentApplicationUrlWithPort() ))), 'guard' => ['web'], 'expiration' => null, 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), 'middleware' => [ 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, ], ];
config/cors.php
<?php return [ 'paths' => [ 'api/*', 'login', 'logout', 'register', 'sanctum/csrf-cookie' ], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];
config/session.php
<?php use Illuminate\Support\Str; return [ 'driver' => env('SESSION_DRIVER', 'file'), 'lifetime' => env('SESSION_LIFETIME', 120), 'expire_on_close' => false, 'encrypt' => false, 'files' => storage_path('framework/sessions'), 'connection' => env('SESSION_CONNECTION'), 'table' => 'sessions', 'store' => env('SESSION_STORE'), 'lottery' => [2, 100], 'cookie' => env( 'SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session' ), 'path' => '/', 'domain' => env('SESSION_DOMAIN'), 'secure' => env('SESSION_SECURE_COOKIE'), 'http_only' => true, 'same_site' => 'lax', 'partitioned' => false, ];
config/auth.php
<?php return [ 'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], // 'users' => [ // 'driver' => 'database', // 'table' => 'users', // ], ], 'passwords' => [ 'users' => [ 'provider' => 'users', 'table' => 'password_reset_tokens', 'expire' => 60, 'throttle' => 60, ], ], 'password_timeout' => 10800, ];
.env
SESSION_DRIVER=cookie SESSION_LIFETIME=120 SESSION_DOMAIN=.example.com SANCTUM_STATEFUL_DOMAINS=https://app.example.com
问题排查与解决步骤
1. 修正Sanctum守卫与认证逻辑的匹配
从更新后的sanctum.php看,你已将guard改回['web'],但需确保登录逻辑使用web守卫处理:
- 检查登录控制器,确认是通过
Auth::attempt(...)(默认守卫为web)或Auth::guard('web')->attempt(...)完成登录,而非api守卫。误用api守卫会导致Session无法正确创建,进而让auth:sanctum无法识别登录状态。
2. 调整全局中间件与API中间件的冲突
你在全局$middleware中添加了StartSession,但web中间件组本身已包含该中间件,且api中间件组默认是无状态的,全局添加会导致Session初始化异常:
- 移除全局
$middleware中的\Illuminate\Session\Middleware\StartSession::class - 保留
web中间件组内的StartSession(默认已包含) api组中的EnsureFrontendRequestsAreStateful会自动为SANCTUM_STATEFUL_DOMAINS内的域名请求处理Session初始化
3. 确认Cookie的Secure属性
由于使用HTTPS域名,需在.env中强制开启Secure Cookie:
SESSION_SECURE_COOKIE=true
否则浏览器不会在HTTPS请求中携带Cookie。
4. 调整SameSite属性
当前session.php中same_site为lax,跨域POST请求(如登录)可能受限制,可临时改为none测试(需配合secure=true):
'same_site' => 'none',
测试通过后可根据业务场景决定是否保留该设置。
5. 清除缓存并重启服务
修改配置后必须清除Laravel缓存,否则修改不生效:
php artisan config:clear php artisan cache:clear
若使用OPcache,需重启PHP服务或清除OPcache缓存。
6. Postman测试注意事项
在Postman中测试时需:
- 在请求Headers中添加
Origin: https://app.example.com - 开启Settings中的
Send cookies选项 - 按顺序请求
/sanctum/csrf-cookie→登录接口→/user接口,确保Cookie被正确携带
内容的提问来源于stack exchange,提问作者sfarzoso
相关产品推荐
相关产品推荐

