Laravel 11 Sanctum跨域(CORS)错误排查求助
问题场景
开发Laravel 11项目,使用Laravel Sanctum为Vue3单页应用(SPA)提供认证服务,通过Docker部署。后端地址为http://shop_backend.localhost:8084,前端地址为http://shop_frontend.localhost:8787,前后端分属不同子域名。请求后端/api/csrf-cookie接口获取CSRF Cookie时,触发CORS错误。
错误信息
Access to XMLHttpRequest at 'http://shop_backend.localhost:8084/api/csrf-cookie' from origin 'http://shop_frontend.localhost:8787' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
现有配置详情
.env配置
APP_NAME=SHOP APP_ENV=local APP_KEY= APP_DEBUG=true APP_TIMEZONE=UTC APP_URL=http://shop_backend.localhost:8084 FRONTEND_URL=http://shop_frontend.localhost:8787 APP_LOCALE=en APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US APP_MAINTENANCE_DRIVER=file APP_MAINTENANCE_STORE=database BCRYPT_ROUNDS=12 LOG_CHANNEL=stack LOG_STACK=single LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=shop DB_USERNAME=test DB_PASSWORD=test SESSION_DRIVER=cookie SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=.localhost BROADCAST_CONNECTION=log FILESYSTEM_DISK=local QUEUE_CONNECTION=database CACHE_STORE=redis CACHE_PREFIX= MEMCACHED_HOST=127.0.0.1 REDIS_HOST=redis REDIS_PASSWORD=null REDIS_PORT=6379 SANCTUM_STATEFUL_DOMAINS=shop_frontend.localhost:8787
config/app.php配置
<?php use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware) { $middleware->statefulApi(); }) ->withExceptions(function (Exceptions $exceptions) { // })->create();
cors.php配置
<?php return [ 'paths' => ['api/*'], 'allowed_methods' => ['*'], 'allowed_origins' => [env('FRONTEND_URL')], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];
sanctum.php配置
<?php use Laravel\Sanctum\Sanctum; return [ 'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS')), 'guard' => ['web'], 'expiration' => 120, 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), 'middleware' => [ 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, ], 'prefix' => 'api', ];
docker-compose.yaml配置
volumes: redis_data: services: database: image: mysql:8.4 container_name: mysql_shop environment: - MYSQL_DATABASE=shop - MYSQL_USER=user - MYSQL_PASSWORD=test - MYSQL_ROOT_PASSWORD=test volumes: - /var/backups/mysql8/shop:/var/lib/mysql ports: - "3306" app: container_name: shop_backend image: webdevops/php-nginx:8.3-alpine volumes: - .:/var/www - ./docker/nginx/main.conf:/opt/docker/etc/nginx/main.conf ports: - "8084:80" links: - database - redis working_dir: /var/www hostname: shop_backend.localhost environment: - "DB_PORT=3306" - "DB_HOST=database" - "DB_PASSWORD=test" - "DB_DATABASE=shop" - "REDIS_ENDPOINT=redis" node: container_name: shop_frontend image: node:lts working_dir: /app command: bash -c "npm i && npm run dev -- --port 8080 --host" volumes: - ../shop-frontend:/app ports: - "8787:8080" user: node hostname: shop_frontend.localhost # phpmyadmin phpmyadmin: image: phpmyadmin restart: always depends_on: - database ports: - "8095:80" environment: PMA_USER: root PMA_PASSWORD: test PMA_HOST: database PMA_ARBITRARY: 1 redis: image: redis:alpine restart: unless-stopped volumes: - redis_data:/data
问题定位与修复方案
1. 扩展CORS覆盖路径
当前cors.php中paths仅配置['api/*'],虽/api/csrf-cookie匹配该规则,但为避免路由匹配异常,建议显式添加Sanctum CSRF路径:
'paths' => ['api/*', '/sanctum/csrf-cookie'],
开发环境可临时设置为['*'],快速验证是否为路径问题。
2. 确保CORS中间件正确应用
Laravel 11需手动将CORS中间件加入API路由组,修改config/app.php中的withMiddleware方法:
->withMiddleware(function (Middleware $middleware) { $middleware->statefulApi(); // 添加CORS中间件到API组 $middleware->api([ \Illuminate\Http\Middleware\HandleCors::class, ]); })
3. 清除Laravel配置缓存
修改配置后需清除缓存,确保新配置生效:
# 进入后端容器 docker exec -it shop_backend bash # 清除配置缓存 php artisan config:clear # 清除路由缓存 php artisan route:clear
4. 检查Nginx配置冲突
使用webdevops/php-nginx镜像时,自定义的main.conf可能添加了额外CORS头,与Laravel的CORS中间件冲突。需确保Nginx配置中不重复设置Access-Control-Allow-Origin等头,若必须设置,需与Laravel配置一致并添加always参数:
add_header Access-Control-Allow-Origin http://shop_frontend.localhost:8787 always; add_header Access-Control-Allow-Credentials true always;
5. 前端Axios配置修正
Vue3项目中需开启Axios的withCredentials,确保Cookie能被携带:
import axios from 'axios'; axios.defaults.baseURL = 'http://shop_backend.localhost:8084/api'; axios.defaults.withCredentials = true; // 请求CSRF Cookie的示例代码 async function getCsrfCookie() { await axios.get('/csrf-cookie'); }
内容的提问来源于stack exchange,提问作者user16010521

