Redesign B3 bordeaux + finish lab-page rework

- Lab page is now read-only with a settings screen for levels/variants;
  variant issuance moved to a large modal on the group page (assign-fragment).
- Header: bordeaux logo and 2px accent underline, bordeaux login/logout/theme
  buttons; smaller radii across the UI; filled secondary/danger buttons.
- Includes prior agent work (login backoff, no-cache pages, API timeouts,
  content tweaks) and fixes (variant usage Map.values, import order).
- Bump static asset version to v=9.
This commit is contained in:
2026-10-02 15:41:16 +03:00
parent c0cf11a5a3
commit 51d1b84297
67 changed files with 3019 additions and 653 deletions

View File

@@ -26,15 +26,18 @@ class JwtAuthenticationFilter(
): Mono<Void> {
val path = exchange.request.path.value()
if (isPublic(path)) {
return chain.filter(exchange)
// Клиентские X-Account-* не должны доходить до сервисов: эти заголовки ставит только gateway.
val stripped = stripAccountHeaders(exchange)
return chain.filter(stripped)
}
val token =
bearerToken(exchange)
?: return unauthorized(exchange, "Требуется вход")
return try {
val jwt = jwtDecoder.decode(token)
val stripped = stripAccountHeaders(exchange)
val request =
exchange.request
stripped.request
.mutate()
.header("X-Account-Id", jwt.subject.orEmpty())
.header("X-Account-Login", jwt.getClaimAsString("login").orEmpty())
@@ -48,6 +51,17 @@ class JwtAuthenticationFilter(
override fun getOrder(): Int = -100
private fun stripAccountHeaders(exchange: ServerWebExchange): ServerWebExchange =
exchange
.mutate()
.request { req ->
req.headers { headers ->
headers.remove("X-Account-Id")
headers.remove("X-Account-Login")
headers.remove("X-Account-Role")
}
}.build()
private fun isPublic(path: String): Boolean =
path.startsWith("/actuator") ||
path == "/api/v1/auth/login" ||