From 14f96f037cdb15c2222760d3c7d0fd17431b5150 Mon Sep 17 00:00:00 2001 From: sxxxxxb Date: Wed, 29 Jul 2026 15:32:46 +0900 Subject: [PATCH] =?UTF-8?q?api=20token=20=EC=86=8C=EC=8A=A4=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/doc/db/jcms_vpp_0.0.5.exerd | Bin 0 -> 63090 bytes .../java/net/jwsi/jcms/vpp/api/ApiClient.java | 55 +++++----------- .../java/net/jwsi/jcms/vpp/api/ApiToken.java | 13 ++++ .../jwsi/jcms/vpp/api/ExternalApiService.java | 62 ++++++++++++++++++ .../jwsi/jcms/vpp/api/RestClientConfig.java | 20 +++--- .../net/jwsi/jcms/vpp/chgr/ChgrService.java | 8 +-- .../net/jwsi/jcms/vpp/chgrHist/ChgrHist.java | 2 +- .../jcms/vpp/chgrHist/ChgrHistService.java | 10 +-- .../jcms/vpp/provider/ProviderService.java | 12 +--- .../jwsi/jcms/vpp/station/StationService.java | 10 +-- .../java/net/jwsi/jcms/vpp/utils/JwtUtil.java | 38 +++++++++++ src/main/resources/application.yml | 7 +- 12 files changed, 151 insertions(+), 86 deletions(-) create mode 100644 src/main/doc/db/jcms_vpp_0.0.5.exerd create mode 100644 src/main/java/net/jwsi/jcms/vpp/api/ApiToken.java create mode 100644 src/main/java/net/jwsi/jcms/vpp/api/ExternalApiService.java create mode 100644 src/main/java/net/jwsi/jcms/vpp/utils/JwtUtil.java diff --git a/src/main/doc/db/jcms_vpp_0.0.5.exerd b/src/main/doc/db/jcms_vpp_0.0.5.exerd new file mode 100644 index 0000000000000000000000000000000000000000..2841eddc28764e63272a9ef794fbabccc6874c4c GIT binary patch literal 63090 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 P)T{vGs)PUl-$eodX#P7I literal 0 HcmV?d00001 diff --git a/src/main/java/net/jwsi/jcms/vpp/api/ApiClient.java b/src/main/java/net/jwsi/jcms/vpp/api/ApiClient.java index 2ac3376..8451d0d 100644 --- a/src/main/java/net/jwsi/jcms/vpp/api/ApiClient.java +++ b/src/main/java/net/jwsi/jcms/vpp/api/ApiClient.java @@ -8,9 +8,7 @@ import net.jwsi.jcms.vpp.station.StationDto; import org.springframework.core.ParameterizedTypeReference; import org.springframework.stereotype.Component; import org.springframework.web.client.RestClient; -import org.springframework.web.util.UriComponentsBuilder; -import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Map; @@ -19,62 +17,39 @@ import java.util.Map; @RequiredArgsConstructor public class ApiClient { - private final RestClient restClient; + private final RestClient externalApiClient; - public ApiResponse> fetchStations(String baseUrl, String token) { - URI uri = UriComponentsBuilder.fromUriString(baseUrl) - .path("/api/st/list") - .build() - .toUri(); - - return restClient.post() - .uri(uri) - .header("Authorization", "Bearer " + token) + public ApiResponse> fetchStations() { + return externalApiClient.post() + .uri("/api/st/list") .body(Collections.emptyMap()) .retrieve() .body(new ParameterizedTypeReference>>() {}); } - public ApiResponse> fetchProviders(String baseUrl, String token) { - URI uri = UriComponentsBuilder.fromUriString(baseUrl) - .path("/api/provider/list") - .build() - .toUri(); - - return restClient.get() - .uri(uri) - .header("Authorization", "Bearer " + token) + public ApiResponse> fetchProviders() { + return externalApiClient.get() + .uri("/api/provider/list") .retrieve() .body(new ParameterizedTypeReference>>() {}); } - public ApiResponse> fetchChgr(String baseUrl, String token) { - URI uri = UriComponentsBuilder.fromUriString(baseUrl) - .path("/api/charger/list") - .build() - .toUri(); - - return restClient.post() - .uri(uri) - .header("Authorization", "Bearer " + token) + public ApiResponse> fetchChgr() { + return externalApiClient.post() + .uri("/api/charger/list") .body(Collections.emptyMap()) .retrieve() .body(new ParameterizedTypeReference>>() {}); } - public ApiResponse> fetchChgrHist(String baseUrl, String token) { - URI uri = UriComponentsBuilder.fromUriString(baseUrl) - .path("/api/charge/hist") - .build() - .toUri(); + public ApiResponse> fetchChgrHist(String startDt, String pageSize) { Map requestBody = Map.of( - "startDt", "2026-07-29", - "pageSize","50" + "startDt", startDt, + "pageSize", pageSize ); - return restClient.post() - .uri(uri) - .header("Authorization", "Bearer " + token) + return externalApiClient.post() + .uri("/api/charge/hist") .body(requestBody) .retrieve() .body(new ParameterizedTypeReference>>() {}); diff --git a/src/main/java/net/jwsi/jcms/vpp/api/ApiToken.java b/src/main/java/net/jwsi/jcms/vpp/api/ApiToken.java new file mode 100644 index 0000000..0025f57 --- /dev/null +++ b/src/main/java/net/jwsi/jcms/vpp/api/ApiToken.java @@ -0,0 +1,13 @@ +package net.jwsi.jcms.vpp.api; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@Getter +public class ApiToken { + private String jwt; + private List roles; +} diff --git a/src/main/java/net/jwsi/jcms/vpp/api/ExternalApiService.java b/src/main/java/net/jwsi/jcms/vpp/api/ExternalApiService.java new file mode 100644 index 0000000..6773d2c --- /dev/null +++ b/src/main/java/net/jwsi/jcms/vpp/api/ExternalApiService.java @@ -0,0 +1,62 @@ +package net.jwsi.jcms.vpp.api; + +import net.jwsi.jcms.vpp.utils.JwtUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.time.LocalDateTime; +import java.util.Map; + +@Service +public class ExternalApiService { + + private final RestClient authRestClient = RestClient.create(); + + @Value("${jcms.api.base-url}") + private String baseUrl; + + @Value("${jcms.api.user-id}") + private String apiUserId; + + @Value("${jcms.api.user-pwd}") + private String apiUserPwd; + + private String cachedToken; + private LocalDateTime tokenExpiryTime; + + public synchronized String getAccessToken() { + if (cachedToken != null && tokenExpiryTime != null && LocalDateTime.now().plusMinutes(1).isBefore(tokenExpiryTime)) { + return cachedToken; + } + + URI uri = UriComponentsBuilder.fromUriString(baseUrl) + .path("/api/auth/token") + .build() + .toUri(); + + Map requestBody = Map.of( + "userId", apiUserId, + "pwd", apiUserPwd + ); + + ApiResponse response = authRestClient.post() + .uri(uri) + .body(requestBody) + .retrieve() + .body(new ParameterizedTypeReference>() {}); + + if (response != null && response.getData() != null) { + ApiToken tokenDto = response.getData(); + this.cachedToken = tokenDto.getJwt(); + this.tokenExpiryTime = JwtUtil.getExpirationTime(this.cachedToken); + + return this.cachedToken; + } + + throw new IllegalStateException("외부 API 토큰 발급에 실패했습니다."); + } +} \ No newline at end of file diff --git a/src/main/java/net/jwsi/jcms/vpp/api/RestClientConfig.java b/src/main/java/net/jwsi/jcms/vpp/api/RestClientConfig.java index e131163..25aadf5 100644 --- a/src/main/java/net/jwsi/jcms/vpp/api/RestClientConfig.java +++ b/src/main/java/net/jwsi/jcms/vpp/api/RestClientConfig.java @@ -1,23 +1,25 @@ package net.jwsi.jcms.vpp.api; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestClient; -import java.time.Duration; - @Configuration public class RestClientConfig { - @Bean - public RestClient restClient() { - SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); - factory.setConnectTimeout((int) Duration.ofSeconds(5).toMillis()); - factory.setReadTimeout((int) Duration.ofSeconds(30).toMillis()); + @Value("${jcms.api.base-url}") + private String baseUrl; + @Bean + public RestClient externalApiClient(ExternalApiService externalApiService) { return RestClient.builder() - .requestFactory(factory) + .baseUrl(baseUrl) + .requestInterceptor((request, body, execution) -> { + String token = externalApiService.getAccessToken(); + request.getHeaders().set("Authorization", "Bearer " + token); + return execution.execute(request, body); + }) .build(); } } \ No newline at end of file diff --git a/src/main/java/net/jwsi/jcms/vpp/chgr/ChgrService.java b/src/main/java/net/jwsi/jcms/vpp/chgr/ChgrService.java index 4294408..071fcde 100644 --- a/src/main/java/net/jwsi/jcms/vpp/chgr/ChgrService.java +++ b/src/main/java/net/jwsi/jcms/vpp/chgr/ChgrService.java @@ -8,7 +8,6 @@ import net.jwsi.jcms.utils.HttpUtil; import net.jwsi.jcms.utils.LoginUtil; import net.jwsi.jcms.vpp.api.ApiClient; import net.jwsi.jcms.vpp.api.ApiResponse; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.jpa.domain.Specification; import org.springframework.scheduling.annotation.Scheduled; @@ -22,11 +21,6 @@ import java.util.stream.Collectors; public class ChgrService extends BaseService { private final ApiClient apiClient; - @Value("${jcms.api.base-url}") - private String baseUrl; - - @Value("${jcms.api.token}") - private String apiToken; public ChgrService(ChgrRepository repository, ApiClient apiClient) { super(repository); this.apiClient = apiClient; @@ -34,7 +28,7 @@ public class ChgrService extends BaseService { @Transactional @Scheduled(cron = "0 0 0 * * *") public void getCharger() { - ApiResponse> response = apiClient.fetchChgr(baseUrl, apiToken); + ApiResponse> response = apiClient.fetchChgr(); if (response == null || !Integer.valueOf(200).equals(response.getCode())) { String msg = (response != null) ? response.getMessage() : "응답 없음"; diff --git a/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHist.java b/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHist.java index a2796ea..e157e98 100644 --- a/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHist.java +++ b/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHist.java @@ -40,7 +40,7 @@ public class ChgrHist extends BaseStEntity { @Column(name = "RECHG_TIME") private String rechgTime; // 충전시간 - @Column(name = "RECH_GWH") + @Column(name = "RECHG_WH") private Integer rechGwh; // 충전량 @Column(name = "RECHG_AMT") diff --git a/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHistService.java b/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHistService.java index abd745e..4ef0b8c 100644 --- a/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHistService.java +++ b/src/main/java/net/jwsi/jcms/vpp/chgrHist/ChgrHistService.java @@ -8,12 +8,12 @@ import net.jwsi.jcms.utils.HttpUtil; import net.jwsi.jcms.utils.LoginUtil; import net.jwsi.jcms.vpp.api.ApiClient; import net.jwsi.jcms.vpp.api.ApiResponse; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.jpa.domain.Specification; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -23,11 +23,6 @@ public class ChgrHistService extends BaseService> response = apiClient.fetchChgrHist(baseUrl, apiToken); + + ApiResponse> response = apiClient.fetchChgrHist(LocalDateTime.now().toString(), "50"); if (response == null || !Integer.valueOf(200).equals(response.getCode())) { String msg = (response != null) ? response.getMessage() : "응답 없음"; diff --git a/src/main/java/net/jwsi/jcms/vpp/provider/ProviderService.java b/src/main/java/net/jwsi/jcms/vpp/provider/ProviderService.java index db0648e..9fe9517 100644 --- a/src/main/java/net/jwsi/jcms/vpp/provider/ProviderService.java +++ b/src/main/java/net/jwsi/jcms/vpp/provider/ProviderService.java @@ -8,15 +8,11 @@ import net.jwsi.jcms.utils.HttpUtil; import net.jwsi.jcms.utils.LoginUtil; import net.jwsi.jcms.vpp.api.ApiClient; import net.jwsi.jcms.vpp.api.ApiResponse; -import net.jwsi.jcms.vpp.station.Station; -import net.jwsi.jcms.vpp.station.StationDto; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.jpa.domain.Specification; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -26,12 +22,6 @@ public class ProviderService extends BaseService> response = apiClient.fetchProviders(baseUrl, apiToken); + ApiResponse> response = apiClient.fetchProviders(); if (response == null || !Integer.valueOf(200).equals(response.getCode())) { String msg = (response != null) ? response.getMessage() : "응답 없음"; diff --git a/src/main/java/net/jwsi/jcms/vpp/station/StationService.java b/src/main/java/net/jwsi/jcms/vpp/station/StationService.java index fdf4eee..772240e 100644 --- a/src/main/java/net/jwsi/jcms/vpp/station/StationService.java +++ b/src/main/java/net/jwsi/jcms/vpp/station/StationService.java @@ -6,15 +6,13 @@ import net.jwsi.jcms.base.BaseService; import net.jwsi.jcms.base.EnumSqlType; import net.jwsi.jcms.utils.HttpUtil; import net.jwsi.jcms.utils.LoginUtil; -import net.jwsi.jcms.vpp.api.ApiResponse; import net.jwsi.jcms.vpp.api.ApiClient; -import org.springframework.beans.factory.annotation.Value; +import net.jwsi.jcms.vpp.api.ApiResponse; import org.springframework.data.domain.Page; import org.springframework.data.jpa.domain.Specification; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -23,11 +21,7 @@ import java.util.stream.Collectors; public class StationService extends BaseService { private final ApiClient apiClient; - @Value("${jcms.api.base-url}") - private String baseUrl; - @Value("${jcms.api.token}") - private String apiToken; public StationService(StationRepository repository, ApiClient apiClient) { super(repository); this.apiClient = apiClient; @@ -36,7 +30,7 @@ public class StationService extends BaseService> response = apiClient.fetchStations(baseUrl, apiToken); + ApiResponse> response = apiClient.fetchStations(); if (response == null || !Integer.valueOf(200).equals(response.getCode())) { String msg = (response != null) ? response.getMessage() : "응답 없음"; diff --git a/src/main/java/net/jwsi/jcms/vpp/utils/JwtUtil.java b/src/main/java/net/jwsi/jcms/vpp/utils/JwtUtil.java new file mode 100644 index 0000000..ef68d2f --- /dev/null +++ b/src/main/java/net/jwsi/jcms/vpp/utils/JwtUtil.java @@ -0,0 +1,38 @@ +package net.jwsi.jcms.vpp.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Base64; + +public class JwtUtil { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static LocalDateTime getExpirationTime(String jwtToken) { + try { + String[] parts = jwtToken.split("\\."); + if (parts.length < 2) { + throw new IllegalArgumentException("올바르지 않은 JWT 토큰 형식입니다."); + } + + String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); + + JsonNode payloadNode = objectMapper.readTree(payloadJson); + if (!payloadNode.has("exp")) { + throw new IllegalStateException("토큰에 exp(만료시간) 필드가 존재하지 않습니다."); + } + + long expSeconds = payloadNode.get("exp").asLong(); + + return LocalDateTime.ofInstant(Instant.ofEpochSecond(expSeconds), ZoneId.systemDefault()); + + } catch (Exception e) { + throw new RuntimeException("토큰 만료 시간 추출 실패", e); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b8d99f0..775bf15 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -19,12 +19,12 @@ jcms: manager-path: cms attr: main-url: /cms/main - new-user-st: 9 # 1: ??, 9:???? + new-user-st: 9 cms-name: VPP cms-title: VPP cms-bg-color: '#499' cms-image-url: /public/images/logo_jcms3.png - copyright: Copyright 2026 ??????????? Inc. + copyright: Copyright 2026 주식회사 진우시스템 Inc. authenticated-patten: /cms/**, /system/**, /api/** pass-url: /cms/main public-url: '' @@ -33,4 +33,5 @@ jcms: days: 30 api: base-url: ${API_BASE_URL:http://dev.jinwoosi.co.kr:8072} - token: ${API_TOKEN} \ No newline at end of file + user-id: ${API_USER_ID:apiuser} + user-pwd: ${API_USER_PWD:apiuser} \ No newline at end of file