-
Notifications
You must be signed in to change notification settings - Fork 0
fix(notification): FCM 서비스 계정 설정 주입 방식 개선 #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
53 changes: 45 additions & 8 deletions
53
notification/src/main/java/com/comatching/notification/global/config/FCMConfig.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,37 +1,74 @@ | ||
| package com.comatching.notification.global.config; | ||
|
|
||
| import java.io.ByteArrayInputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.util.Base64; | ||
|
|
||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.core.io.ClassPathResource; | ||
|
|
||
| import com.google.auth.oauth2.GoogleCredentials; | ||
| import com.google.firebase.FirebaseApp; | ||
| import com.google.firebase.FirebaseOptions; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Value; | ||
| import jakarta.annotation.PostConstruct; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.core.io.Resource; | ||
| import org.springframework.core.io.ResourceLoader; | ||
| import org.springframework.util.StringUtils; | ||
|
|
||
| @Slf4j | ||
| @Configuration | ||
| @RequiredArgsConstructor | ||
| public class FCMConfig { | ||
|
|
||
| private final ResourceLoader resourceLoader; | ||
|
|
||
| // 운영: base64 인코딩된 서비스 계정 JSON 을 env 로 주입받는다. | ||
| // (.env 파일이 멀티라인 값을 지원하지 않아 JSON 원문 대신 base64 한 줄로 넣는다) | ||
| @Value("${fcm.service-account-b64:}") | ||
| private String serviceAccountB64; | ||
|
|
||
| // 로컬 폴백: 기존과 같은 classpath 파일. | ||
| @Value("${fcm.credentials:classpath:serviceAccountKey.json}") | ||
| private String credentialsLocation; | ||
|
|
||
| // 운영(aws 프로파일)에서만 true. 키가 없으면 기동을 깨서 배포 시점에 드러낸다. | ||
| @Value("${fcm.required:false}") | ||
| private boolean required; | ||
|
|
||
| @PostConstruct | ||
| public void init() { | ||
| try { | ||
| try (InputStream serviceAccount = openCredentials()) { | ||
| if (serviceAccount == null) { | ||
| if (required) { | ||
| throw new IllegalStateException("FCM 서비스 계정 키가 없다 (env FCM_SERVICE_ACCOUNT_B64 미설정)"); | ||
| } | ||
| log.warn("FCM 키 없음 - 푸시 비활성화 상태로 기동"); | ||
| return; | ||
| } | ||
|
|
||
| InputStream serviceAccount = new ClassPathResource("serviceAccountKey.json").getInputStream(); | ||
| FirebaseOptions options = FirebaseOptions.builder() | ||
| .setCredentials(GoogleCredentials.fromStream(serviceAccount)) | ||
| .build(); | ||
| .setCredentials(GoogleCredentials.fromStream(serviceAccount)) | ||
| .build(); | ||
|
|
||
| if (FirebaseApp.getApps().isEmpty()) { | ||
| FirebaseApp.initializeApp(options); | ||
| log.info("🔥 FirebaseApp Initialized"); | ||
| } | ||
| } catch (IOException | IllegalArgumentException e) { | ||
| // 키가 "있는데" 깨진 것(base64 오류·JSON 파싱 실패)은 환경 불문 잘못된 상태다. 삼키지 않는다. | ||
| throw new IllegalStateException("FirebaseApp 초기화 실패", e); | ||
| } | ||
| } | ||
|
|
||
| } catch (Exception e) { | ||
| log.error("❌ FirebaseApp Init Failed", e); | ||
| private InputStream openCredentials() throws IOException { | ||
| if (StringUtils.hasText(serviceAccountB64)) { | ||
| return new ByteArrayInputStream(Base64.getDecoder().decode(serviceAccountB64.trim())); | ||
| } | ||
| Resource resource = resourceLoader.getResource(credentialsLocation); | ||
| return resource.exists() ? resource.getInputStream() : null; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
application.yml은 프로파일과 무관하게 항상 로드되는 base 설정이라, 여기서fcm.required: true를 켜면 local 을 포함한 모든 프로파일에서 fail-fast 가 적용됩니다.FCMConfig.init()에서required가 true 인 상태로 base64 env 도, classpath 의serviceAccountKey.json도 없으면IllegalStateException이 던져져 기동 자체가 깨지는데, PR 설명의 "로컬 환경에서는 classpath 자격 증명 파일을 폴백으로 사용", "운영 환경의 키 누락 시에만 기동 실패"라는 의도와 정반대입니다.FCMConfig.java의 주석("운영(aws 프로파일)에서만 true")과@Value("${fcm.required:false}")기본값과도 어긋나고,application-aws.yml에 이미 같은 값을 넣어둔 게 완전히 무의미해집니다.base 는 false 로 두고
application-aws.yml에서만 true 로 덮어써야 의도한 계층 구조가 성립합니다.