From 9a10bc807e248a4bbebc7ab093acde2fb7132fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=98=84=EC=88=98?= Date: Wed, 7 Jan 2026 14:02:53 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20preRegister=20Device=20FingerPrintin?= =?UTF-8?q?g=20=EC=8B=9C=EB=8F=84=20=ED=9A=9F=EC=88=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=B2=B4=ED=81=AC=20=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/PreRegisterService.java | 22 ++++------------- .../service/PreRegisterServiceTest.java | 24 +++++++++---------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/backend/src/main/java/com/back/api/preregister/service/PreRegisterService.java b/backend/src/main/java/com/back/api/preregister/service/PreRegisterService.java index f23cc8e8..9ba8bead 100644 --- a/backend/src/main/java/com/back/api/preregister/service/PreRegisterService.java +++ b/backend/src/main/java/com/back/api/preregister/service/PreRegisterService.java @@ -99,10 +99,7 @@ public PreRegisterResponse register(Long eventId, Long userId, PreRegisterCreate // 모든 검증 통과 후 SMS 인증 플래그 삭제 deleteSmsVerificationFlag(request.phoneNumber()); - // Fingerprint 성공 기록 (이벤트별, 사전등록 액션) - if (fingerprintService != null && visitorId != null) { - fingerprintService.recordAttempt(visitorId, eventId, FingerprintService.ACTION_PRE_REGISTER, true); - } + // Fingerprint 기록은 FingerprintRecordFilter에서 자동 처리됨 (중복 방지) return PreRegisterResponse.from(preRegister); } @@ -128,23 +125,14 @@ public PreRegisterResponse register(Long eventId, Long userId, PreRegisterCreate ) ); - // Fingerprint 성공 기록 (이벤트별, 사전등록 액션) - if (fingerprintService != null && visitorId != null) { - fingerprintService.recordAttempt(visitorId, eventId, FingerprintService.ACTION_PRE_REGISTER, true); - } + // Fingerprint 기록은 FingerprintRecordFilter에서 자동 처리됨 (중복 방지) return PreRegisterResponse.from(savedPreRegister); } catch (ErrorException e) { - // Fingerprint 실패 기록 (검증 실패) - 이벤트별, 사전등록 액션 - if (fingerprintService != null && visitorId != null) { - fingerprintService.recordAttempt(visitorId, eventId, FingerprintService.ACTION_PRE_REGISTER, false); - } + // Fingerprint 기록은 FingerprintRecordFilter에서 자동 처리됨 (중복 방지) throw e; } catch (Exception e) { - // Fingerprint 실패 기록 (시스템 에러) - 이벤트별, 사전등록 액션 - if (fingerprintService != null && visitorId != null) { - fingerprintService.recordAttempt(visitorId, eventId, FingerprintService.ACTION_PRE_REGISTER, false); - } + // Fingerprint 기록은 FingerprintRecordFilter에서 자동 처리됨 (중복 방지) throw e; } } @@ -172,7 +160,7 @@ public List getMyPreRegister(Long userId) { .map(preRegister -> { Event event = preRegister.getEvent(); String imageUrl = null; - if(event.getImageUrl() != null && !event.getImageUrl().isBlank()) { + if (event.getImageUrl() != null && !event.getImageUrl().isBlank()) { imageUrl = s3PresignedService.issueDownloadUrl(event.getImageUrl()); } diff --git a/backend/src/test/java/com/back/api/preregister/service/PreRegisterServiceTest.java b/backend/src/test/java/com/back/api/preregister/service/PreRegisterServiceTest.java index 386cb35d..a6eb6353 100644 --- a/backend/src/test/java/com/back/api/preregister/service/PreRegisterServiceTest.java +++ b/backend/src/test/java/com/back/api/preregister/service/PreRegisterServiceTest.java @@ -1267,7 +1267,7 @@ void register_Success_ReRegisterWithVisitorId() { class FingerprintRecording { @Test - @DisplayName("신규 등록 성공 시 visitorId로 성공 기록 (line 133)") + @DisplayName("신규 등록 성공 시 Service에서 Fingerprint 기록하지 않음 (FingerprintRecordFilter에서 처리)") void register_Success_RecordFingerprintSuccess() { // given PreRegisterCreateRequest request = PreRegisterRequestFactory.fakePreRegisterRequest( @@ -1284,12 +1284,12 @@ void register_Success_RecordFingerprintSuccess() { visitorId ); - // then: Fingerprint 성공 기록 호출 검증 - verify(fingerprintService).recordAttempt(eq(visitorId), any(Long.class), eq("pre_register"), eq(true)); + // then: Service에서는 Fingerprint 기록하지 않음 (중복 방지 - FingerprintRecordFilter에서 자동 처리) + verify(fingerprintService, never()).recordAttempt(any(), any(), any(), anyBoolean()); } @Test - @DisplayName("재등록 성공 시 visitorId로 성공 기록 (line 104)") + @DisplayName("재등록 성공 시 Service에서 Fingerprint 기록하지 않음 (FingerprintRecordFilter에서 처리)") void register_ReRegister_RecordFingerprintSuccess() { // given: CANCELED 상태의 사전등록 PreRegister canceledPreRegister = PreRegister.builder() @@ -1315,12 +1315,12 @@ void register_ReRegister_RecordFingerprintSuccess() { visitorId ); - // then: Fingerprint 성공 기록 호출 검증 - verify(fingerprintService).recordAttempt(eq(visitorId), any(Long.class), eq("pre_register"), eq(true)); + // then: Service에서는 Fingerprint 기록하지 않음 (중복 방지 - FingerprintRecordFilter에서 자동 처리) + verify(fingerprintService, never()).recordAttempt(any(), any(), any(), anyBoolean()); } @Test - @DisplayName("ErrorException 발생 시 visitorId로 실패 기록 (lines 140, 142)") + @DisplayName("ErrorException 발생 시 Service에서 Fingerprint 기록하지 않음 (FingerprintRecordFilter에서 처리)") void register_ErrorException_RecordFingerprintFailure() { // given: 잘못된 생년월일로 ErrorException 유발 PreRegisterCreateRequest request = PreRegisterRequestFactory.fakePreRegisterRequest( @@ -1339,12 +1339,12 @@ void register_ErrorException_RecordFingerprintFailure() { .isInstanceOf(ErrorException.class) .hasMessage(PreRegisterErrorCode.INVALID_USER_INFO.getMessage()); - // then: Fingerprint 실패 기록 호출 검증 - verify(fingerprintService).recordAttempt(eq(visitorId), any(Long.class), eq("pre_register"), eq(false)); + // then: Service에서는 Fingerprint 기록하지 않음 (중복 방지 - FingerprintRecordFilter에서 자동 처리) + verify(fingerprintService, never()).recordAttempt(any(), any(), any(), anyBoolean()); } @Test - @DisplayName("ErrorException 발생 시 visitorId로 실패 기록 - 약관 미동의 (lines 140, 142)") + @DisplayName("약관 미동의 시 Service에서 Fingerprint 기록하지 않음 (FingerprintRecordFilter에서 처리)") void register_TermsNotAgreed_RecordFingerprintFailure() { // given: 약관 미동의로 ErrorException 유발 PreRegisterCreateRequest request = PreRegisterRequestFactory.fakePreRegisterRequestWithoutTerms( @@ -1363,8 +1363,8 @@ void register_TermsNotAgreed_RecordFingerprintFailure() { .isInstanceOf(ErrorException.class) .hasMessage(PreRegisterErrorCode.TERMS_NOT_AGREED.getMessage()); - // then: Fingerprint 실패 기록 호출 검증 - verify(fingerprintService).recordAttempt(eq(visitorId), any(Long.class), eq("pre_register"), eq(false)); + // then: Service에서는 Fingerprint 기록하지 않음 (중복 방지 - FingerprintRecordFilter에서 자동 처리) + verify(fingerprintService, never()).recordAttempt(any(), any(), any(), anyBoolean()); } // Note: Lines 143, 146, 148 (일반 Exception catch 블록)은 통합 테스트로 커버하기 어려움 From abfac2ae4f7baadae97f8ac107baf9e252c9d5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=98=84=EC=88=98?= Date: Wed, 7 Jan 2026 15:24:21 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20test-reCAPTCHA.html=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/test-recaptcha-token-generator.html | 317 -------------------- 1 file changed, 317 deletions(-) delete mode 100644 backend/test-recaptcha-token-generator.html diff --git a/backend/test-recaptcha-token-generator.html b/backend/test-recaptcha-token-generator.html deleted file mode 100644 index d3ba42be..00000000 --- a/backend/test-recaptcha-token-generator.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - - reCAPTCHA Token Generator - 백엔드 테스트용 - - - - -
-

🔐 reCAPTCHA Token Generator

-

백엔드 API 테스트용 토큰 생성기

- -
-

📌 사용 중인 키 정보

-

Site Key (프로덕션): 6LdqrjQsAAAAAH135gDhYqN6aLCcM4x3UhLKkZsY

-

Secret Key (백엔드 .env): 6LdqrjQsAAAAAEBtE16lbtXPhlaKHjPLFfWYVu7s

-

- ✅ 이 키들은 실제 프로덕션 키입니다. Google이 실제로 검증을 수행합니다. -

-
- - - -
-
생성된 reCAPTCHA 토큰:
-
- - -
-
✅ 클립보드에 복사되었습니다!
-
- -
-

📋 Swagger로 테스트하는 방법

-
    -
  1. "토큰 생성하기" 버튼을 클릭해서 토큰 발급
  2. -
  3. 생성된 토큰을 복사 (📋 복사 버튼 클릭)
  4. -
  5. http://localhost:8080/swagger-ui/index.html 접속
  6. -
  7. PreRegister API 섹션에서 POST /api/v1/events/{eventId}/pre-registers 선택
  8. -
  9. "Try it out" 클릭
  10. -
  11. X-Recaptcha-Token 필드에 복사한 토큰 붙여넣기
  12. -
  13. eventId 입력 (예: 1)
  14. -
  15. Execute 클릭
  16. -
-
- -
-

⚠️ 주의사항

-
    -
  • 토큰은 2분 후 만료됩니다. 오래된 토큰은 재생성하세요.
  • -
  • 한 번 사용한 토큰은 재사용 불가합니다. 새로운 API 테스트마다 토큰을 재생성하세요.
  • -
  • 실제 프로덕션 키로 변경 시, 이 HTML 파일의 Site Key를 교체하세요.
  • -
  • 백엔드 .env 파일의 GOOGLE_RECAPTCHA_SECRET_KEY가 위의 Secret Key와 일치하는지 확인하세요.
  • -
-
- -
-

🔧 다른 프로덕션 키로 변경하는 방법

-

1. Google reCAPTCHA Admin Console에서 Site - Key 발급

-

2. 이 HTML 파일의 <script> 태그에서 Site Key 교체:

- - <script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script> - -

3. 백엔드 .env 파일에 Secret Key 설정:

- - GOOGLE_RECAPTCHA_SECRET_KEY=YOUR_SECRET_KEY - -
-
- - - -