/
Al
/
TESamples
Обзор
Документация
Войти
/
Al
/
TESamples
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
apps/spring/chain-service/src/main/java/com/tokenexchange/service/ClockSkewObserver.java
61 строка
3 KB
Al
Initial Commit
11 май 2026, 17:40
11 май 2026, 17:40
0a04577
Код
Авторство
О чём код?
package com.tokenexchange.service; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.stereotype.Component; import java.time.Instant; import java.util.concurrent.atomic.AtomicLong; /** * Наблюдение за расхождением часов между Keycloak и сервисом. Реализует §9 * Рекомендаций для клиента «Расхождение часов» * (docs/client-recommendations.md#9). * * <p>Метрика {@code jwt_clock_skew_seconds} (gauge) экспортирует наибольший * наблюдаемый skew с момента старта. Если |skew| > 2 × tolerance — отдельная * метрика-counter (для алерта). * * <p>Здесь — только наблюдение, не отказ в обслуживании. Жёсткую проверку * выполняет Spring Security ({@code JwtTimestampValidator}) внутри * {@code spring-boot-starter-oauth2-resource-server}. */ @Component public class ClockSkewObserver { private static final Logger log = LoggerFactory.getLogger(ClockSkewObserver.class); private final MeterRegistry registry; private final long toleranceSeconds; private final AtomicLong lastObserved = new AtomicLong(0); public ClockSkewObserver( MeterRegistry registry, @Value("${CLOCK_SKEW_TOLERANCE_SECONDS:60}") long toleranceSeconds, @Value("${spring.application.name:chain-service}") String serviceName ) { this.registry = registry; this.toleranceSeconds = toleranceSeconds; registry.gauge("jwt_clock_skew_seconds", Tags.of("service", serviceName), lastObserved, AtomicLong::doubleValue); } public long observe(Jwt jwt) { Instant iat = jwt.getIssuedAt(); if (iat == null) return 0; long now = Instant.now().getEpochSecond(); long skew = now - iat.getEpochSecond(); lastObserved.set(skew); if (Math.abs(skew) > 2 * toleranceSeconds) { log.warn("Clock skew {} s exceeds 2 × tolerance ({} s) — possible clock_skew_suspected", skew, toleranceSeconds); registry.counter("jwt_clock_skew_violations_total").increment(); } return skew; } }