refactor(cors): централизовать CORS на gateway, убрать per-service из pcp-ui-service

CORS-политика (allowedOriginPatterns:* + allowCredentials) переезжает в единый
globalcors на pcp-gateway-service. После сворачивания фронта на gateway браузер
ходит к бэкендам только через него (same-origin via Vite/nginx), поэтому
per-service CORS в pcp-ui-service/WebConfig.kt стал мёртвым грузом. globalcors
оставлен как страховка от cross-origin напрямую к gateway.
This commit is contained in:
Дмитрий Соловьев
2026-06-10 14:04:29 +03:00
parent ab3a787da5
commit 3c4ebcd7d3
2 changed files with 13 additions and 62 deletions
+13
View File
@@ -10,6 +10,19 @@ spring:
server:
# WebFlux-вариант Spring Cloud Gateway (Boot 4 / Spring Cloud 2025.1).
webflux:
# CORS теперь живёт ТОЛЬКО здесь — единая точка на edge. Раньше дублировался
# per-service (pcp-ui-service/WebConfig.kt), но после сворачивания фронта на
# gateway браузер ходит к бэкендам строго через него. Страховка от cross-origin
# к самому gateway (dev напрямую, LAN-адрес рабочей станции): allowedOriginPatterns
# "*" совместим с allowCredentials=true (в отличие от allowedOrigins "*").
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns: "*"
allowedMethods: "*"
allowedHeaders: "*"
allowCredentials: true
maxAge: 3600
routes:
# --- Доменные сервисы. Префикс /api/pcp-<x> СРЕЗАЕТСЯ (StripPrefix=2 убирает
# 2 сегмента: api + pcp-<x>), т.е. /api/pcp-tgu/api/plans -> бэкенд /api/plans.
@@ -1,62 +0,0 @@
package space.nstart.pcp.slots_service.configuration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import org.springframework.web.filter.CorsFilter
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
class WebConfig : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
// Внутренний ops-инструмент: UI открывают с разных хостов/IP (localhost,
// LAN-адрес рабочей станции, прод-сборка). Любой явный список origin'ов рано
// или поздно не совпадает с фактическим адресом UI → POST/PUT/DELETE отбивается
// как «Invalid CORS request» (same-origin GET проходит, т.к. идёт без Origin).
// Поэтому разрешаем любой origin. allowedOriginPatterns("*") совместим с
// allowCredentials=true (в отличие от allowedOrigins("*")).
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600)
}
// Альтернативный вариант через CorsFilter
@Bean
fun corsFilter(): CorsFilter {
val source = UrlBasedCorsConfigurationSource()
val config = CorsConfiguration().apply {
allowCredentials = true
// Любой origin — см. комментарий в addCorsMappings.
allowedOriginPatterns = listOf("*")
// Разрешенные заголовки
allowedHeaders = listOf(
"Origin",
"Content-Type",
"Accept",
"Authorization",
"X-Requested-With",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
)
// Разрешенные методы
allowedMethods = listOf(
"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD"
)
// Заголовки, доступные клиенту
exposedHeaders = listOf(
"Access-Control-Allow-Origin",
"Access-Control-Allow-Credentials"
)
maxAge = 3600L
}
source.registerCorsConfiguration("/**", config)
return CorsFilter(source)
}
}