From a4531e8d90dec444d1c716a49626c28a7c28c74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Sat, 21 Feb 2026 21:55:08 +0900 Subject: [PATCH] =?UTF-8?q?fix:=ED=92=88=EB=AA=A9=EA=B4=80=EB=A6=AC=20FG?= =?UTF-8?q?=20=EC=88=98=EC=8B=9D=20=EC=82=B0=EC=B6=9C=20401=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FormulaApiService의 Bearer token 조회를 session('api_explorer_token')에서 ApiTokenService 기반으로 변경 - resolveApiToken() 메서드 추가: 세션 토큰 확인 → 만료시 HMAC 토큰 교환 - DocumentTemplateApiController와 동일한 인증 패턴 적용 Co-Authored-By: Claude Opus 4.6 --- app/Services/FormulaApiService.php | 43 +++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/app/Services/FormulaApiService.php b/app/Services/FormulaApiService.php index 16810fe6..74386266 100644 --- a/app/Services/FormulaApiService.php +++ b/app/Services/FormulaApiService.php @@ -14,7 +14,7 @@ class FormulaApiService * - URL: https://nginx/api/v1/quotes/calculate/bom (Docker nginx 컨테이너) * - Host 헤더: api.sam.kr (nginx가 올바른 서버 블록으로 라우팅) * - SSL 우회: withoutVerifying() (내부 자체 서명 인증서) - * - 인증: X-API-KEY 헤더 (FLOW_TESTER_API_KEY 환경변수) + * - 인증: X-API-KEY + Bearer token (ApiTokenService 토큰 교환) * * @param string $finishedGoodsCode 완제품 코드 (예: FG-KQTS01) * @param array $variables 입력 변수 ['W0' => 3000, 'H0' => 3000, 'QTY' => 1] @@ -27,8 +27,8 @@ public function calculateBom(string $finishedGoodsCode, array $variables, int $t $apiKey = config('api-explorer.default_environments.0.api_key') ?: env('FLOW_TESTER_API_KEY', ''); - // Bearer token: 세션에 저장된 API 토큰 사용 (헤더 인증 UI에서 발급) - $bearerToken = session('api_explorer_token'); + // Bearer token: ApiTokenService로 세션 토큰 확인, 만료 시 재발급 + $bearerToken = $this->resolveApiToken($tenantId); $headers = [ 'Host' => 'api.sam.kr', @@ -80,4 +80,41 @@ public function calculateBom(string $finishedGoodsCode, array $variables, int $t ]; } } + + /** + * API Bearer token 확보 (세션 토큰 → 만료/미존재 시 재발급) + */ + private function resolveApiToken(int $tenantId): ?string + { + $tokenService = new ApiTokenService; + + // 세션에 유효한 토큰이 있으면 사용 + if (! $tokenService->isTokenExpired()) { + return $tokenService->getSessionToken(); + } + + // 토큰 만료 또는 미존재 → 교환 시도 + $userId = auth()->id(); + if (! $userId) { + Log::warning('[FormulaApiService] 인증된 사용자 없음 - API 토큰 교환 불가'); + + return null; + } + + $result = $tokenService->exchangeToken($userId, $tenantId); + if ($result['success']) { + $tokenService->storeTokenInSession( + $result['data']['access_token'], + $result['data']['expires_in'] + ); + + return $result['data']['access_token']; + } + + Log::warning('[FormulaApiService] API 토큰 교환 실패', [ + 'error' => $result['error'] ?? '', + ]); + + return null; + } }