Laravel Sanctum跨域授权配置异常:NuxtJS登录报419错误
NuxtJS + Laravel 9 Sanctum 跨域登录419错误排查
我用NuxtJS做客户端,Laravel 9 API做后端集成Laravel Sanctum,因前后端域名不同,登录时触发“419 unknown status”未授权错误。已遵循官方文档完成配置(含.env配置尝试)但问题仍存在,相关配置代码如下:
config/cors.php
<?php return [ 'paths' => ['api/*', 'login', 'logout', 'sanctum/csrf-cookie', 'api'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];
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,https://mango-grass-0b3b8cd10.3.azurestaticapps.net/', Sanctum::currentApplicationUrlWithPort() ))), // 'guard' => ['web'], 'expiration' => null, 'middleware' => [ 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, ], ];
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', ];
config/kernel.php
<?php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful; class Kernel extends HttpKernel { protected $middleware = [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \Fruitcake\Cors\HandleCors::class, ]; protected $middlewareGroups = [ 'web' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, // \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \Fruitcake\Cors\HandleCors::class, ], 'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:60,1', \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class, \Fruitcake\Cors\HandleCors::class, ], ]; protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \App\Http\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ]; }
nuxt.config.js
auth: { redirect: { home: '/', logout: '/login', login: '/login', }, plugins: [ '~/plugins/auth.js', { src: '~/plugins/sweetalert2.js', mode: 'client' }, { src: '~/plugins/VueDebounce.js' }, ], strategies: { laravelSanctum: { provider: 'laravel/sanctum', url: backendUrl, endpoints: { login: { url: '/api/login', }, logout: { url: '/api/logout', }, }, }, }, },
login.vue
const handleSubmit = async () => { if (email.value === '' || password === '') { Swal.fire({ title: '¡Información!', text: '¡Existen campos obligatorios vacíos.!', icon: 'info', confirmButtonText: 'Aceptar', }) } else { loaderButton.value = true await $auth .loginWith('laravelSanctum', { data: { email: email.value, password: password.value }, }) .then((response) => { backendService.value.getMe().then((responseMe) => { localStorage.setItem('UserName', responseMe.name) localStorage.setItem('UserEmail', responseMe.email) localStorage.setItem('token', response.data.token) getPermissionRol(responseMe.permission) router.push('/') }) }) .catch((error) => { if (error.code === 'ECONNREFUSED') { Swal.fire({ title: '¡Error!', text: 'No se puede conectar con el servidor. Verifique su conexión a internet o inténtelo más tarde.', icon: 'error', confirmButtonText: 'Aceptar', }) } else if (error.request && error.request.message) { Swal.fire({ title: '¡Error!', text: error.request.message, icon: 'error', confirmButtonText: 'Aceptar', }) } else { Swal.fire({ title: '¡Error!', text: '¡Error!', icon: 'error', confirmButtonText: 'Aceptar', }) } }) .finally(() => { loaderButton.value = false }) }
排查修复关键点
移除重复CORS中间件
kernel.php中同时注册了\Illuminate\Http\Middleware\HandleCors::class和\Fruitcake\Cors\HandleCors::class,二者冲突,保留其中一个即可(推荐保留Fruitcake版本)。修正Sanctum状态域配置
- 去掉
SANCTUM_STATEFUL_DOMAINS中域名末尾的斜杠,比如把https://mango-grass-0b3b8cd10.3.azurestaticapps.net/改为https://mango-grass-0b3b8cd10.3.azurestaticapps.net - 建议直接在
.env中明确设置该值,避免默认拼接的不确定性:SANCTUM_STATEFUL_DOMAINS=localhost:3000,https://mango-grass-0b3b8cd10.3.azurestaticapps.net
- 去掉
调整Session跨域配置
- 跨域场景下,
SESSION_DOMAIN设为后端根域名(如后端是api.example.com则设为.example.com),或留空让Laravel自动处理 - 若前后端均为HTTPS,将
SESSION_SECURE_COOKIE设为true,同时same_site改为'none'
- 跨域场景下,
完善Nuxt Auth配置
在laravelSanctum策略中添加withCredentials: true,确保Cookie能跨域传递:strategies: { laravelSanctum: { provider: 'laravel/sanctum', url: backendUrl, withCredentials: true, // 新增此行 endpoints: { login: { url: '/api/login' }, logout: { url: '/api/logout' }, }, }, }优化Sanctum中间件配置
注释掉sanctum.php中middleware里的verify_csrf_token项,Sanctum会自动处理CSRF验证,无需额外配置:'middleware' => [ // 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, ],验证CSRF Cookie获取
在浏览器开发者工具的Application -> Cookies中,确认登录请求前已成功获取XSRF-TOKEN和会话Cookie,若未获取,检查cors.php的paths是否正确包含sanctum/csrf-cookie。
内容的提问来源于stack exchange,提问作者Diego Chavez
相关产品推荐
相关产品推荐

