diff --git a/src/main/java/gc/mda/signal_batch/domain/gis/controller/GisControllerV2.java b/src/main/java/gc/mda/signal_batch/domain/gis/controller/GisControllerV2.java index 495171a..a3476da 100644 --- a/src/main/java/gc/mda/signal_batch/domain/gis/controller/GisControllerV2.java +++ b/src/main/java/gc/mda/signal_batch/domain/gis/controller/GisControllerV2.java @@ -191,7 +191,11 @@ public class GisControllerV2 { ) @RequestBody VesselTracksRequest request, HttpServletRequest httpRequest) { - return gisServiceV2.getVesselTracksV2(request, getClientIp(httpRequest)); + return gisServiceV2.getVesselTracksV2(request, getClientIp(httpRequest), getClientId(httpRequest)); + } + + private String getClientId(HttpServletRequest request) { + return gc.mda.signal_batch.global.config.WebSocketStompConfig.extractClientIdFromRequest(request); } private String getClientIp(HttpServletRequest request) { diff --git a/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java b/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java index 42ec069..b3d6478 100644 --- a/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java +++ b/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java @@ -285,7 +285,7 @@ public class GisServiceV2 { /** * 선박별 항적 조회 V2 (캐시 + Semaphore + 간소화 + ChnPrmShip enrichment) */ - public List getVesselTracksV2(VesselTracksRequest request, String clientIp) { + public List getVesselTracksV2(VesselTracksRequest request, String clientIp, String clientId) { String queryId = "rest-vessels-" + UUID.randomUUID().toString().substring(0, 8); long startMs = System.currentTimeMillis(); boolean slotAcquired = false; @@ -329,7 +329,7 @@ public class GisServiceV2 { result.size(), request.getVessels().size(), dailyTrackCacheManager.isEnabled(), request.isIncludeChnPrmShip()); - enqueueRestMetric(queryId, request, result, startMs, clientIp); + enqueueRestMetric(queryId, request, result, startMs, clientIp, clientId); return result; @@ -347,7 +347,7 @@ public class GisServiceV2 { } private void enqueueRestMetric(String queryId, VesselTracksRequest request, - List result, long startMs, String clientIp) { + List result, long startMs, String clientIp, String clientId) { try { int totalPoints = result.stream().mapToInt(CompactVesselTrack::getPointCount).sum(); long responseBytes = (long) result.size() * 200 + (long) totalPoints * 40; @@ -367,6 +367,7 @@ public class GisServiceV2 { .elapsedMs(System.currentTimeMillis() - startMs) .status("COMPLETED") .clientIp(clientIp) + .clientId(clientId) .build()); } catch (Exception e) { log.debug("Failed to enqueue REST metric: {}", e.getMessage()); diff --git a/src/main/java/gc/mda/signal_batch/global/config/WebSocketStompConfig.java b/src/main/java/gc/mda/signal_batch/global/config/WebSocketStompConfig.java index e8f0c46..419c913 100644 --- a/src/main/java/gc/mda/signal_batch/global/config/WebSocketStompConfig.java +++ b/src/main/java/gc/mda/signal_batch/global/config/WebSocketStompConfig.java @@ -235,42 +235,44 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer { return "unknown"; } - /** - * GC_SESSION 쿠키에서 JWT payload의 email 클레임 추출. - * JWT 검증은 nginx auth_request에서 이미 완료 — 여기서는 payload 디코딩만 수행. - */ private String extractEmailFromJwtCookie(HttpServletRequest request) { - Cookie[] cookies = request.getCookies(); - if (cookies == null) return null; + return extractClientIdFromRequest(request); + } + } - String token = null; - for (Cookie cookie : cookies) { - if ("GC_SESSION".equals(cookie.getName())) { - token = cookie.getValue(); - break; - } + /** + * GC_SESSION 쿠키에서 JWT payload의 email 클레임 추출 (REST/WebSocket 공용). + * JWT 검증은 nginx auth_request에서 이미 완료 — 여기서는 payload 디코딩만 수행. + */ + public static String extractClientIdFromRequest(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) return null; + + String token = null; + for (Cookie cookie : cookies) { + if ("GC_SESSION".equals(cookie.getName())) { + token = cookie.getValue(); + break; } - if (token == null || token.isEmpty()) return null; + } + if (token == null || token.isEmpty()) return null; - try { - // JWT: header.payload.signature — payload만 Base64URL 디코딩 - String[] parts = token.split("\\."); - if (parts.length < 2) return null; + try { + String[] parts = token.split("\\."); + if (parts.length < 2) return null; - String payload = new String(Base64.getUrlDecoder().decode(parts[1])); - // 간단한 JSON 파싱 (Jackson 의존 없이): "email":"value" 추출 - int emailIdx = payload.indexOf("\"email\""); - if (emailIdx < 0) return null; + String payload = new String(Base64.getUrlDecoder().decode(parts[1])); + int emailIdx = payload.indexOf("\"email\""); + if (emailIdx < 0) return null; - int colonIdx = payload.indexOf(':', emailIdx); - int quoteStart = payload.indexOf('"', colonIdx + 1); - int quoteEnd = payload.indexOf('"', quoteStart + 1); - if (quoteStart < 0 || quoteEnd < 0) return null; + int colonIdx = payload.indexOf(':', emailIdx); + int quoteStart = payload.indexOf('"', colonIdx + 1); + int quoteEnd = payload.indexOf('"', quoteStart + 1); + if (quoteStart < 0 || quoteEnd < 0) return null; - return payload.substring(quoteStart + 1, quoteEnd); - } catch (Exception e) { - return null; - } + return payload.substring(quoteStart + 1, quoteEnd); + } catch (Exception e) { + return null; } } } \ No newline at end of file