diff --git a/.env.example b/.env.example index c38c119..3d953aa 100644 --- a/.env.example +++ b/.env.example @@ -40,6 +40,22 @@ APP_MAINTENANCE_DRIVER=file # 内置 PHP 开发服务器 worker 数量(多核本机可酌情打开) # PHP_CLI_SERVER_WORKERS=4 +# ============================================================================= +# CORS(跨域;config/cors.php) +# ============================================================================= + +# 浏览器跨域访问 API 的来源白名单,逗号分隔(协议+域名+可选端口) +# 示例: +# CORS_ALLOWED_ORIGINS=https://admin.example.com,https://partner-a.com +CORS_ALLOWED_ORIGINS= +# 可选:来源正则模式(需要受控通配时再用) +# CORS_ALLOWED_ORIGINS_PATTERNS=^https://([a-z0-9-]+)\.partner\.example\.com$ +CORS_ALLOWED_ORIGINS_PATTERNS= +# 预检缓存秒数;0 表示不缓存 +CORS_MAX_AGE=0 +# 是否允许跨站 Cookie(仅在确实需要浏览器跨站会话时设 true) +CORS_SUPPORTS_CREDENTIALS=false + # ============================================================================= # 密码哈希(config/hashing.php) # ============================================================================= diff --git a/config/cors.php b/config/cors.php new file mode 100644 index 0000000..db89b4c --- /dev/null +++ b/config/cors.php @@ -0,0 +1,87 @@ + trim($origin), + explode(',', (string) env('CORS_ALLOWED_ORIGINS', '')) +), static fn (string $origin): bool => $origin !== '')); + +$allowedOriginsPatterns = array_values(array_filter(array_map( + static fn (string $pattern): string => trim($pattern), + explode(',', (string) env('CORS_ALLOWED_ORIGINS_PATTERNS', '')) +), static fn (string $pattern): bool => $pattern !== '')); + +return [ + /* + |-------------------------------------------------------------------------- + | CORS Paths + |-------------------------------------------------------------------------- + | + | Only API and broadcasting/auth endpoints need CORS handling. + | + */ + 'paths' => ['api/*', 'broadcasting/auth'], + + /* + |-------------------------------------------------------------------------- + | Allowed Methods + |-------------------------------------------------------------------------- + */ + 'allowed_methods' => ['*'], + + /* + |-------------------------------------------------------------------------- + | Allowed Origins + |-------------------------------------------------------------------------- + | + | Use explicit domain whitelist in production. Do not use *. + | + */ + 'allowed_origins' => $allowedOrigins, + + /* + |-------------------------------------------------------------------------- + | Allowed Origin Patterns + |-------------------------------------------------------------------------- + | + | Optional regex-style patterns for controlled wildcard subdomains. + | + */ + 'allowed_origins_patterns' => $allowedOriginsPatterns, + + /* + |-------------------------------------------------------------------------- + | Allowed Headers + |-------------------------------------------------------------------------- + */ + 'allowed_headers' => ['*'], + + /* + |-------------------------------------------------------------------------- + | Exposed Headers + |-------------------------------------------------------------------------- + */ + 'exposed_headers' => [], + + /* + |-------------------------------------------------------------------------- + | Max Age + |-------------------------------------------------------------------------- + */ + 'max_age' => (int) env('CORS_MAX_AGE', 0), + + /* + |-------------------------------------------------------------------------- + | Supports Credentials + |-------------------------------------------------------------------------- + | + | Enable only if browser cross-site cookie auth is required. + | + */ + 'supports_credentials' => filter_var( + env('CORS_SUPPORTS_CREDENTIALS', false), + FILTER_VALIDATE_BOOL + ), +]; +