feat(gateway): сервис pcp-gateway-service + сворачивание маршрутизации фронта на него
- новый Spring Cloud Gateway (WebFlux): доменные маршруты /api/pcp-<x>/**
со StripPrefix=2, /api/stations без среза пути, catch-all /api/** → ui-service;
опциональная JWT-валидация на edge (gateway.security.jwt-enabled, по умолчанию off)
- config-repo: pcp-gateway-service.yaml (маршруты) + порт/адрес gateway в реестрах
application-{local,docker-local,dev}
- build: репозитории переведены на mavenCentral (nstart-proxy закомментирован),
включены mavenLocal/gradlePluginPortal; settings: include модуля
- pcp-tgu-ui-service: vite-proxy и nginx.conf свёрнуты на единый /api → gateway
(вместо набора per-service правил)
- deploy: сервис gateway в docker-compose; helm-чарт pcp-gateway-service
- CI: .gitlab/ci/pcp-gateway-service.yml + проводка в .gitlab-ci.yml
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
ARG RUNTIME_IMAGE=repo.nstart.cloud/bellsoft/liberica-openjre-alpine:21.0.5
|
||||
FROM ${RUNTIME_IMAGE}
|
||||
|
||||
ENV JAVA_OPTS=""
|
||||
|
||||
ADD ./build/libs/*.jar /app.jar
|
||||
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app.jar"]
|
||||
@@ -0,0 +1,50 @@
|
||||
group = "space.nstart.pcp"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
kotlin("plugin.spring")
|
||||
id("org.springframework.boot")
|
||||
id("io.spring.dependency-management")
|
||||
}
|
||||
|
||||
version = "0.0.1"
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of((property("versions.java") as String).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll("-Xjsr305=strict")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Реактивный edge: Spring Cloud Gateway (WebFlux-вариант) + конфиг из config-server.
|
||||
// Маршруты живут в config-repo/pcp-gateway-service.yaml — единый источник правды.
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-gateway-server-webflux")
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-config")
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
// Валидация JWT на edge (Keycloak/new-start-id) — включается флагом gateway.security.jwt-enabled.
|
||||
// Тянет reactive Spring Security (ServerHttpSecurity/@EnableWebFluxSecurity).
|
||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||
runtimeOnly("io.micrometer:micrometer-registry-prometheus")
|
||||
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("versions.spring.cloud")}")
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package space.nstart.pcp_gateway_service
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
/**
|
||||
* Единая точка входа в бэкенд для фронта (pcp-tgu-ui-service): reverse-proxy поверх
|
||||
* микросервисов. Маршрутная таблица — в config-repo/pcp-gateway-service.yaml и ссылается
|
||||
* на реестр `pcp.services.*`, так что топологию знает только gateway, а не браузер.
|
||||
*/
|
||||
@SpringBootApplication
|
||||
class GatewayApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<GatewayApplication>(*args)
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package space.nstart.pcp_gateway_service.config
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
|
||||
/**
|
||||
* Политика edge. Две взаимоисключающие цепочки, переключаемые флагом
|
||||
* `gateway.security.jwt-enabled` (завязан на режим входа фронта):
|
||||
* - выключено (anonymous, текущий дефолт) — пропускаем всё: поведение как при прямых вызовах;
|
||||
* - включено (закрытый контур new-start-id) — валидируем Bearer JWT один раз здесь, дальше
|
||||
* gateway по умолчанию пробрасывает заголовок Authorization вниз к сервисам.
|
||||
*
|
||||
* Когда JWT выключен, `spring.security.oauth2.resourceserver.jwt.issuer-uri` не задаётся,
|
||||
* поэтому JwtDecoder не создаётся и старт не падает из-за пустого issuer.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebFluxSecurity
|
||||
class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "gateway.security", name = ["jwt-enabled"], havingValue = "true")
|
||||
fun securedChain(http: ServerHttpSecurity): SecurityWebFilterChain =
|
||||
http
|
||||
.csrf { it.disable() }
|
||||
.authorizeExchange { exchanges ->
|
||||
exchanges
|
||||
.pathMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.pathMatchers("/healthz", "/actuator/**").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
}
|
||||
.oauth2ResourceServer { it.jwt {} }
|
||||
.build()
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
prefix = "gateway.security",
|
||||
name = ["jwt-enabled"],
|
||||
havingValue = "false",
|
||||
matchIfMissing = true,
|
||||
)
|
||||
fun openChain(http: ServerHttpSecurity): SecurityWebFilterChain =
|
||||
http
|
||||
.csrf { it.disable() }
|
||||
.authorizeExchange { it.anyExchange().permitAll() }
|
||||
.build()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
spring:
|
||||
application:
|
||||
name: pcp-gateway-service
|
||||
profiles:
|
||||
default: local
|
||||
config:
|
||||
import: "configserver:"
|
||||
cloud:
|
||||
config:
|
||||
uri: ${CONFIG_SERVER_URI:http://localhost:8888}
|
||||
fail-fast: ${CONFIG_SERVER_FAIL_FAST:true}
|
||||
profile: ${SPRING_CLOUD_CONFIG_PROFILE:${SPRING_PROFILES_ACTIVE:${spring.profiles.default}}}
|
||||
label: ${SPRING_CLOUD_CONFIG_LABEL:master}
|
||||
Reference in New Issue
Block a user