From 3f2887cea580548b13326b167a35286d558ee7c6 Mon Sep 17 00:00:00 2001 From: 40food <40food@naver.com> Date: Thu, 29 Jan 2026 19:58:48 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/LogoutController.java | 2 -- .../auth/controller/OAuthController.java | 2 -- .../unity/domain/auth/dto/OAuthUserInfo.java | 6 ++--- .../unity/domain/auth/model/OAuthToken.java | 6 ++--- .../auth/service/AuthSessionServiceImpl.java | 5 ---- .../auth/service/LogoutServiceImpl.java | 1 - .../domain/auth/service/OAuthServiceImpl.java | 1 - .../auth/service/RefreshTokenServiceImpl.java | 17 +----------- .../auth/service/oauth/GoogleOAuthClient.java | 3 +-- .../call/service/RecordingServiceImpl.java | 6 ++--- .../unity/domain/call/util/Converter.java | 15 ++++------- .../controller/RecommendController.java | 1 - .../recommend/service/RecommendService.java | 26 ------------------ .../domain/stt/service/SttServiceImpl.java | 27 +++++-------------- .../summary/service/SummaryService.java | 2 -- .../ureca/unity/domain/user/model/User.java | 8 +++--- .../unity/global/config/OAuthTokenCrypto.java | 8 ++---- .../unity/global/config/WebMvcConfig.java | 2 +- .../exception/GlobalExceptionHandler.java | 3 --- .../security/JwtAuthenticationFilter.java | 6 ----- .../unity/global/security/JwtProvider.java | 1 - src/main/resources/application.yml | 1 - 22 files changed, 29 insertions(+), 120 deletions(-) diff --git a/src/main/java/com/ureca/unity/domain/auth/controller/LogoutController.java b/src/main/java/com/ureca/unity/domain/auth/controller/LogoutController.java index 02eaf1a..46c4867 100644 --- a/src/main/java/com/ureca/unity/domain/auth/controller/LogoutController.java +++ b/src/main/java/com/ureca/unity/domain/auth/controller/LogoutController.java @@ -31,12 +31,10 @@ public void logout( ) { logoutService.logout(refreshToken); - // 1. 현재 표준 쿠기 (Path=/) 삭제 response.addCookie( CookieUtils.deleteRefreshTokenCookie(cookieSecure) ); - // 2. 레거시 쿠키(Path=/api/auth)도 삭제 (과거 잔재 청소) response.addCookie(CookieUtils.deleteRefreshTokenCookie(cookieSecure, "/api/auth", "Lax")); response.addCookie(CookieUtils.deleteRefreshTokenCookie(cookieSecure, "/api/auth", "Strict")); } diff --git a/src/main/java/com/ureca/unity/domain/auth/controller/OAuthController.java b/src/main/java/com/ureca/unity/domain/auth/controller/OAuthController.java index bea21d9..0e8c8d8 100644 --- a/src/main/java/com/ureca/unity/domain/auth/controller/OAuthController.java +++ b/src/main/java/com/ureca/unity/domain/auth/controller/OAuthController.java @@ -39,11 +39,9 @@ public OAuthLoginResponse login( ) { OAuthLoginResult result = oAuthService.login(OAuthProvider.from(provider), code); - // 1. 레거시(/api/auth) 쿠키 제거 (예전 SameSite가 Strict였다면 Strict로 한 번 더) response.addCookie(CookieUtils.deleteRefreshTokenCookie(cookieSecure, "/api/auth", "Strict")); response.addCookie(CookieUtils.deleteRefreshTokenCookie(cookieSecure, "/api/auth", "Lax")); - // 2. 정상(/) 쿠키 설정 response.addCookie( CookieUtils.createRefreshTokenCookie( result.refreshToken(), diff --git a/src/main/java/com/ureca/unity/domain/auth/dto/OAuthUserInfo.java b/src/main/java/com/ureca/unity/domain/auth/dto/OAuthUserInfo.java index f41b74f..8c89e54 100644 --- a/src/main/java/com/ureca/unity/domain/auth/dto/OAuthUserInfo.java +++ b/src/main/java/com/ureca/unity/domain/auth/dto/OAuthUserInfo.java @@ -9,8 +9,8 @@ @Builder public class OAuthUserInfo { - private final String provider; // google / naver / kakao - private final String providerId; // OAuth 제공자 고유 ID - private final String email; // nullable 가능 + private final String provider; + private final String providerId; + private final String email; private final String name; } diff --git a/src/main/java/com/ureca/unity/domain/auth/model/OAuthToken.java b/src/main/java/com/ureca/unity/domain/auth/model/OAuthToken.java index e4654a5..bfbe813 100644 --- a/src/main/java/com/ureca/unity/domain/auth/model/OAuthToken.java +++ b/src/main/java/com/ureca/unity/domain/auth/model/OAuthToken.java @@ -10,8 +10,8 @@ public class OAuthToken { private Long id; private Long userId; - private String provider; // google / naver / kakao + private String provider; private String accessToken; - private String refreshToken; // nullable - private LocalDateTime expiresAt; // nullable + private String refreshToken; + private LocalDateTime expiresAt; } diff --git a/src/main/java/com/ureca/unity/domain/auth/service/AuthSessionServiceImpl.java b/src/main/java/com/ureca/unity/domain/auth/service/AuthSessionServiceImpl.java index 0b50cfd..5b49787 100644 --- a/src/main/java/com/ureca/unity/domain/auth/service/AuthSessionServiceImpl.java +++ b/src/main/java/com/ureca/unity/domain/auth/service/AuthSessionServiceImpl.java @@ -29,7 +29,6 @@ public class AuthSessionServiceImpl implements AuthSessionService { public MeResponse getMe(HttpServletRequest request) { String refreshToken = extractRefreshToken(request); - // (1) refresh JWT 서명 + type 검증 Long jwtUserId; try { jwtUserId = jwtProvider.getUserId(refreshToken, "refresh"); @@ -37,22 +36,18 @@ public MeResponse getMe(HttpServletRequest request) { throw new CustomException(ErrorCode.REFRESH_TOKEN_INVALID); } - // (2) DB에 저장된 토큰인지 확인 RefreshToken saved = refreshTokenMapper.findByToken(refreshToken) .orElseThrow(() -> new CustomException(ErrorCode.REFRESH_TOKEN_INVALID)); - // (3) 만료 체크 if (saved.getExpiresAt() == null || saved.getExpiresAt().isBefore(Instant.now())) { refreshTokenMapper.deleteByToken(refreshToken); throw new CustomException(ErrorCode.REFRESH_TOKEN_EXPIRED); } - // (4) 토큰의 userId 일치 체크 if (!saved.getUserId().equals(jwtUserId)) { throw new CustomException(ErrorCode.REFRESH_TOKEN_INVALID); } - // (5) 유저 조회 User user = userMapper.findById(saved.getUserId()) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); diff --git a/src/main/java/com/ureca/unity/domain/auth/service/LogoutServiceImpl.java b/src/main/java/com/ureca/unity/domain/auth/service/LogoutServiceImpl.java index 39aa5b7..2eb28a5 100644 --- a/src/main/java/com/ureca/unity/domain/auth/service/LogoutServiceImpl.java +++ b/src/main/java/com/ureca/unity/domain/auth/service/LogoutServiceImpl.java @@ -18,7 +18,6 @@ public class LogoutServiceImpl implements LogoutService { @Override public void logout(String refreshToken) { -// refreshToken 없어도 로그아웃은 성공 if (refreshToken == null || refreshToken.isBlank()) { log.info("Logout: no refreshToken provided"); return; diff --git a/src/main/java/com/ureca/unity/domain/auth/service/OAuthServiceImpl.java b/src/main/java/com/ureca/unity/domain/auth/service/OAuthServiceImpl.java index 7bda2b6..6c90390 100644 --- a/src/main/java/com/ureca/unity/domain/auth/service/OAuthServiceImpl.java +++ b/src/main/java/com/ureca/unity/domain/auth/service/OAuthServiceImpl.java @@ -56,7 +56,6 @@ public OAuthLoginResult login(OAuthProvider provider, String authorizationCode) ); } - // 재가입이면 true, 기존이면 false return createLoginResult(anyUser.getId(), wasDeleted, provider.value(), tokenInfo); }) .orElseGet(() -> { diff --git a/src/main/java/com/ureca/unity/domain/auth/service/RefreshTokenServiceImpl.java b/src/main/java/com/ureca/unity/domain/auth/service/RefreshTokenServiceImpl.java index 2b07bb5..92862ed 100644 --- a/src/main/java/com/ureca/unity/domain/auth/service/RefreshTokenServiceImpl.java +++ b/src/main/java/com/ureca/unity/domain/auth/service/RefreshTokenServiceImpl.java @@ -53,11 +53,8 @@ public void saveRefreshToken(Long userId, String refreshToken) { @Override public TokenResponse refreshAccessToken(HttpServletRequest request, HttpServletResponse response) { - - // 1. Cookie에서 refreshToken 추출 String refreshToken = extractRefreshToken(request); - // 1-1. JWT 서명 검증 (DB 조회 전) Long jwtUserId; try { jwtUserId = jwtProvider.getUserId(refreshToken, "refresh"); @@ -65,7 +62,6 @@ public TokenResponse refreshAccessToken(HttpServletRequest request, throw new CustomException(ErrorCode.REFRESH_TOKEN_INVALID); } - // 2. DB 조회 RefreshToken savedToken = refreshTokenMapper.findByToken(refreshToken) .orElseThrow(() -> new CustomException(ErrorCode.REFRESH_TOKEN_INVALID) @@ -75,10 +71,8 @@ public TokenResponse refreshAccessToken(HttpServletRequest request, throw new CustomException(ErrorCode.REFRESH_TOKEN_INVALID); } - // 3. 만료 체크 if (savedToken.getExpiresAt().isBefore(Instant.now())) { - // 만료된 토큰은 즉시 삭제 후 예외 반환 (rotation 로직 미진입) - refreshTokenMapper.deleteByToken(refreshToken); // 만료 토큰 정리 + refreshTokenMapper.deleteByToken(refreshToken); throw new CustomException(ErrorCode.REFRESH_TOKEN_EXPIRED); } @@ -88,22 +82,14 @@ public TokenResponse refreshAccessToken(HttpServletRequest request, throw new CustomException(ErrorCode.REFRESH_TOKEN_INVALID); } - // 4. 기존 refreshToken 폐기 (Rotation 로직 진입) int deletedCount = refreshTokenMapper.deleteByToken(refreshToken); if (deletedCount == 0) { throw new CustomException(ErrorCode.REFRESH_TOKEN_INVALID); } - // 5. 새 Access + Refresh 발급 TokenResponse accessToken = jwtIssuer.issueAccessToken(userId); - - // 6. 새 refreshToken 발급 String newRefreshToken = jwtIssuer.issueRefreshToken(userId); - - // 7. DB 저장 saveRefreshToken(userId, newRefreshToken); - - // 8. 새 refreshToken 쿠키 설정 response.addCookie(CookieUtils.createRefreshTokenCookie( newRefreshToken, jwtProperties.refreshExpirationSeconds(), @@ -111,7 +97,6 @@ public TokenResponse refreshAccessToken(HttpServletRequest request, ) ); - // 9. accessToken만 반환 return accessToken; } diff --git a/src/main/java/com/ureca/unity/domain/auth/service/oauth/GoogleOAuthClient.java b/src/main/java/com/ureca/unity/domain/auth/service/oauth/GoogleOAuthClient.java index a5e630d..36769f4 100644 --- a/src/main/java/com/ureca/unity/domain/auth/service/oauth/GoogleOAuthClient.java +++ b/src/main/java/com/ureca/unity/domain/auth/service/oauth/GoogleOAuthClient.java @@ -38,7 +38,7 @@ public class GoogleOAuthClient implements OAuthClient { @Override public OAuthAuthResult authenticate(String authorizationCode) { - Map token = getTokenResponse(authorizationCode); // access/refresh/expires_in + Map token = getTokenResponse(authorizationCode); String accessToken = token.get("access_token").toString(); String refreshToken = token.get("refresh_token") != null ? String.valueOf(token.get("refresh_token")) : null; @@ -48,7 +48,6 @@ public OAuthAuthResult authenticate(String authorizationCode) { expiresIn = Long.valueOf(String.valueOf(token.get("expires_in"))); } catch (NumberFormatException e) { log.warn("Google token response has non-numeric expires_in: {}", token.get("expires_in")); - // expires_in 파싱 실패 시 null로 처리 } } diff --git a/src/main/java/com/ureca/unity/domain/call/service/RecordingServiceImpl.java b/src/main/java/com/ureca/unity/domain/call/service/RecordingServiceImpl.java index fa2cdc0..377f05c 100644 --- a/src/main/java/com/ureca/unity/domain/call/service/RecordingServiceImpl.java +++ b/src/main/java/com/ureca/unity/domain/call/service/RecordingServiceImpl.java @@ -40,7 +40,6 @@ public class RecordingServiceImpl implements RecordingService { private final CounselingResultMapper sttMapper; private final SummaryMapper summaryMapper; - //@Value 주입이 완료된 후, 호출 시점에 WebClient 빌드 private WebClient getWebClient() { String authStr = customerId + ":" + customerSecret; String auth = Base64.getEncoder().encodeToString(authStr.getBytes()); @@ -55,7 +54,6 @@ private WebClient getWebClient() { @Override public String acquire(String channelName, String uid) { log.info("[Agora] Acquire 요청 시작 - channel: {}, uid: {}", channelName, uid); - // 전체 Body Map body = Map.of( "cname",channelName, "uid", uid, @@ -165,10 +163,10 @@ public void stop(String resourceId, String sid, String channelName, String uid, throw new CustomException(ErrorCode.INTERNAL_SERVER_ERROR); } - //s3의 파일->wav로 변경->stt + //s3 파일->wav로 변경->stt CompletableFuture.runAsync(() -> { try { - Thread.sleep(10000); //TODO:차후 lambda로 호출되면 동작하도록 개선 + Thread.sleep(10000); //차후 lambda로 호출되면 동작하도록 개선 String m3u8Url = String.format("https://%s.s3.ap-northeast-2.amazonaws.com/recordings/%s/%s_%s.m3u8", s3Bucket, channelName, sid, channelName); log.info("변환 시작: {}", m3u8Url); diff --git a/src/main/java/com/ureca/unity/domain/call/util/Converter.java b/src/main/java/com/ureca/unity/domain/call/util/Converter.java index f557019..8be6c42 100644 --- a/src/main/java/com/ureca/unity/domain/call/util/Converter.java +++ b/src/main/java/com/ureca/unity/domain/call/util/Converter.java @@ -14,27 +14,22 @@ public class Converter { public File convertM3u8ToWav(String m3u8Url) { File target=null; try { - // 1. 결과물이 저장될 임시 파일 생성 target = File.createTempFile("recording_", ".wav"); - // 2. 오디오 설정 (Google/Whisper STT 권장 사양) + // 오디오 설정 AudioAttributes audio = new AudioAttributes(); -// audio.setCodec("pcm_s16le"); // WAV 표준 코덱 - audio.setSamplingRate(16000); // 16kHz (STT 최적화) + audio.setSamplingRate(16000); audio.setBitRate(256000); - audio.setChannels(1); // 모노 (화자 분리 및 인식률 향상) + audio.setChannels(1); - // 3. 인코딩 설정 EncodingAttributes attrs = new EncodingAttributes(); attrs.setOutputFormat("wav"); attrs.setAudioAttributes(audio); - // 4. 변환 실행 (URL로부터 직접 읽기) Encoder encoder = new Encoder(); - // 아고라 S3 URL을 MultimediaObject에 직접 넣습니다. encoder.encode(new MultimediaObject(new URL(m3u8Url)), target, attrs); - log.info("WAV 변환 성공: {}", target.getAbsolutePath()); + log.info("[WAV] 변환 성공: {}", target.getAbsolutePath()); return target; } catch (Exception e) { @@ -42,7 +37,7 @@ public File convertM3u8ToWav(String m3u8Url) { if (target != null && target.exists() && !target.delete()) { log.warn("임시 파일 삭제 실패: {}", target.getAbsolutePath()); } - throw new IllegalStateException("m3u8 -> wav 변환 실패", e); + throw new IllegalStateException("[WAV] m3u8 -> wav 변환 실패", e); } } } diff --git a/src/main/java/com/ureca/unity/domain/recommend/controller/RecommendController.java b/src/main/java/com/ureca/unity/domain/recommend/controller/RecommendController.java index ea3f256..f26e36c 100644 --- a/src/main/java/com/ureca/unity/domain/recommend/controller/RecommendController.java +++ b/src/main/java/com/ureca/unity/domain/recommend/controller/RecommendController.java @@ -45,7 +45,6 @@ public RecommendResponse get(@PathVariable long summaryId) { // 전체 추천 조회 @GetMapping("/me") public RecommendResponse getAll() { - // undefined 'currentUserId' 제거 — 서비스의 카테고리 기반 조회 재사용 return recommendService.getRandomByCategory(); } } diff --git a/src/main/java/com/ureca/unity/domain/recommend/service/RecommendService.java b/src/main/java/com/ureca/unity/domain/recommend/service/RecommendService.java index 9aa97fa..4ee6f44 100644 --- a/src/main/java/com/ureca/unity/domain/recommend/service/RecommendService.java +++ b/src/main/java/com/ureca/unity/domain/recommend/service/RecommendService.java @@ -107,30 +107,4 @@ public RecommendResponse getRandomByCategory() { response.setItems(results); return response; } - - -// public List getRecommendationsWithFallback(long summaryId) { -// List items = recommendMapper.selectBySummaryId(summaryId); -// -// // 추천 없으면 빈 리스트 처리 -// if (items == null) { -// items = new ArrayList<>(); -// } -// -// // 카테고리별로 그룹화 -// Map> byCategory = items.stream() -// .collect(Collectors.groupingBy(RecommendItem::getCategoryId)); -// -// List categories = categoryMapper.selectAll(); -// for (Category c : categories) { -// if (!byCategory.containsKey(c.getCategoryId()) || byCategory.get(c.getCategoryId()).isEmpty()) { -// // 추천 없으면 fallback -// List fallback = recommendMapper.selectRandomByCategory(c.getCategoryId()); -// items.addAll(fallback); -// } -// } -// -// // score=0, rankNo=0인 fallback도 이미 Mapper에서 설정됨 -// return items; -// } } diff --git a/src/main/java/com/ureca/unity/domain/stt/service/SttServiceImpl.java b/src/main/java/com/ureca/unity/domain/stt/service/SttServiceImpl.java index f64731f..edeedfd 100644 --- a/src/main/java/com/ureca/unity/domain/stt/service/SttServiceImpl.java +++ b/src/main/java/com/ureca/unity/domain/stt/service/SttServiceImpl.java @@ -35,16 +35,12 @@ public class SttServiceImpl implements SttService { @Override public CounselingResult startStt(File file, long userId, CounselingResult job) { String gcsUri = null; - try { if (!file.exists() || file.length() == 0) { throw new RuntimeException("오디오 파일이 존재하지 않거나 비어있습니다."); } + log.info("[STT] 시작 - file: {}, size: {} bytes", file.getAbsolutePath(), file.length()); - log.info("STT 시작 (Long Audio) - file: {}, size: {} bytes", - file.getAbsolutePath(), file.length()); - - // 1️⃣ GCS 업로드 String objectName = "recordings/" + userId + "/" + job.getCounselingResultId() + ".wav"; @@ -53,26 +49,21 @@ public CounselingResult startStt(File file, long userId, CounselingResult job) { objectName, file.toPath() ); + log.info("[GCS] 업로드 완료: {}", gcsUri); - log.info("GCS 업로드 완료: {}", gcsUri); - - // 2️⃣ RecognitionAudio (URI 기반) RecognitionAudio audio = RecognitionAudio.newBuilder() .setUri(gcsUri) .build(); - // 3️⃣ Long Audio 최적화 설정 RecognitionConfig config = RecognitionConfig.newBuilder() .setLanguageCode("ko-KR") .setEncoding(RecognitionConfig.AudioEncoding.ENCODING_UNSPECIFIED) -// .setSampleRateHertz(16000) // wav 실제 값과 반드시 일치 .setAudioChannelCount(1) .setEnableAutomaticPunctuation(true) .setUseEnhanced(true) .setModel("latest_long") .build(); - // 4️⃣ Google 인증 Resource resource = new DefaultResourceLoader().getResource(keyPath); try (InputStream is = resource.getInputStream()) { @@ -92,7 +83,7 @@ public CounselingResult startStt(File file, long userId, CounselingResult job) { > future = speechClient.longRunningRecognizeAsync(config, audio); - // ⏳ 긴 파일 대기 (최대 30분) + //대기 최대 30분 LongRunningRecognizeResponse response = future.get(30, TimeUnit.MINUTES); @@ -101,11 +92,11 @@ public CounselingResult startStt(File file, long userId, CounselingResult job) { .collect(Collectors.joining(" ")); if (text.isBlank()) { - log.warn("STT 결과가 비어있음"); + log.warn("[STT] 결과가 비어있음"); job.setStatus("FAIL"); job.setTexts("No speech detected."); } else { - log.info("STT 완료 (length={} chars)", text.length()); + log.info("[STT] 완료 (length={} chars)", text.length()); job.setStatus("SUCCESS"); job.setTexts(text); } @@ -113,22 +104,18 @@ public CounselingResult startStt(File file, long userId, CounselingResult job) { } } catch (Exception e) { - log.error("STT 처리 중 오류 발생", e); + log.error("[STT] 처리 중 오류 발생", e); job.setStatus("FAIL"); job.setTexts("Error: " + e.getMessage()); } finally { - // 5️⃣ 로컬 파일 삭제 if (file.exists()) { boolean deleted = file.delete(); - log.info("로컬 wav 파일 삭제: {}", deleted); + log.info("[WAV] 로컬 wav 파일 삭제: {}", deleted); } } - // 6️⃣ DB 업데이트 sttMapper.updateResult(job); - - // 7️⃣ 성공 시 요약 호출 if ("SUCCESS".equals(job.getStatus())) { summaryService.createSummary( job.getCounselingResultId(), diff --git a/src/main/java/com/ureca/unity/domain/summary/service/SummaryService.java b/src/main/java/com/ureca/unity/domain/summary/service/SummaryService.java index 9f752d3..9de62cb 100644 --- a/src/main/java/com/ureca/unity/domain/summary/service/SummaryService.java +++ b/src/main/java/com/ureca/unity/domain/summary/service/SummaryService.java @@ -57,9 +57,7 @@ public void createSummary(Long counselingResultId, Long userId, String counselin summaryMapper.updateStatus(summaryId, "SUCCESS"); - // (현재는 반환값 사용 안 하니 생성만 유지) new SummaryResponse(gemini.getTitle(), gemini.getSubject(), keywords, points); - } catch (Exception e) { summaryMapper.updateStatus(summaryId, "FAIL"); throw new IllegalStateException(e); diff --git a/src/main/java/com/ureca/unity/domain/user/model/User.java b/src/main/java/com/ureca/unity/domain/user/model/User.java index 45f8a5b..b7b9470 100644 --- a/src/main/java/com/ureca/unity/domain/user/model/User.java +++ b/src/main/java/com/ureca/unity/domain/user/model/User.java @@ -13,13 +13,13 @@ public class User { private Long id; - private String provider; // google / naver / kakao - private String providerId; // OAuth 제공자 고유 ID + private String provider; + private String providerId; - private String email; // nullable + private String email; private String name; - private String role; // ROLE_USER + private String role; private Instant termsAgreedAt; private LocalDateTime deletedAt; diff --git a/src/main/java/com/ureca/unity/global/config/OAuthTokenCrypto.java b/src/main/java/com/ureca/unity/global/config/OAuthTokenCrypto.java index 1389393..c92daef 100644 --- a/src/main/java/com/ureca/unity/global/config/OAuthTokenCrypto.java +++ b/src/main/java/com/ureca/unity/global/config/OAuthTokenCrypto.java @@ -15,15 +15,13 @@ public class OAuthTokenCrypto { private static final String ALG = "AES"; private static final String TRANSFORM = "AES/GCM/NoPadding"; - private static final int IV_LEN = 12; // GCM 권장 12 bytes + private static final int IV_LEN = 12; private static final int TAG_BITS = 128; private final byte[] keyBytes; private final SecureRandom random = new SecureRandom(); public OAuthTokenCrypto(@Value("${security.oauth-token.secret}") String secret) { - // 최소 수정 버전: secret을 16/24/32 bytes로 맞춰 쓰는 걸 권장 - // 여기서는 "UTF-8 바이트" 기준으로 32바이트로 잘라/패딩 처리 byte[] raw = secret.getBytes(StandardCharsets.UTF_8); this.keyBytes = new byte[32]; for (int i = 0; i < this.keyBytes.length; i++) { @@ -43,7 +41,6 @@ public String encrypt(String plain) { byte[] ct = cipher.doFinal(plain.getBytes(StandardCharsets.UTF_8)); - // 저장 포맷: base64( iv + ciphertext ) byte[] out = new byte[iv.length + ct.length]; System.arraycopy(iv, 0, out, 0, iv.length); System.arraycopy(ct, 0, out, iv.length, ct.length); @@ -58,7 +55,7 @@ public String decrypt(String enc) { if (enc == null) return null; try { byte[] in = Base64.getDecoder().decode(enc); - if (in.length < IV_LEN + 1) return enc; // 방어: 평문이 들어온 경우 그냥 반환 + if (in.length < IV_LEN + 1) return enc; byte[] iv = new byte[IV_LEN]; byte[] ct = new byte[in.length - IV_LEN]; @@ -73,7 +70,6 @@ public String decrypt(String enc) { byte[] pt = cipher.doFinal(ct); return new String(pt, StandardCharsets.UTF_8); } catch (Exception e) { - // 방어: 기존 데이터가 평문/다른 포맷이면 그냥 원문 반환(마이그레이션 단계에서 유용) return enc; } } diff --git a/src/main/java/com/ureca/unity/global/config/WebMvcConfig.java b/src/main/java/com/ureca/unity/global/config/WebMvcConfig.java index f91e736..d78d556 100644 --- a/src/main/java/com/ureca/unity/global/config/WebMvcConfig.java +++ b/src/main/java/com/ureca/unity/global/config/WebMvcConfig.java @@ -12,7 +12,7 @@ public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") // 모든 엔드포인트 + registry.addMapping("/**") .allowedOrigins(allowedOrigins.split("\\s*,\\s*")) .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") .allowCredentials(true); diff --git a/src/main/java/com/ureca/unity/global/exception/GlobalExceptionHandler.java b/src/main/java/com/ureca/unity/global/exception/GlobalExceptionHandler.java index da2e1c5..2a60657 100644 --- a/src/main/java/com/ureca/unity/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/ureca/unity/global/exception/GlobalExceptionHandler.java @@ -15,7 +15,6 @@ public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); - /* 잘못된 요청 파라미터 (provider 등) */ @ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleIllegalArgumentException(IllegalArgumentException e) { @@ -23,7 +22,6 @@ public String handleIllegalArgumentException(IllegalArgumentException e) { return "잘못된 요청입니다."; } - /* 입력값 검증 실패 (@NotBlank 등) */ @ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleValidationException(ConstraintViolationException e) { @@ -31,7 +29,6 @@ public String handleValidationException(ConstraintViolationException e) { return "입력값 검증에 실패했습니다."; } - /* 그 외 서버 내부 오류 */ @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public String handleException(Exception e) { diff --git a/src/main/java/com/ureca/unity/global/security/JwtAuthenticationFilter.java b/src/main/java/com/ureca/unity/global/security/JwtAuthenticationFilter.java index 077797f..ee68354 100644 --- a/src/main/java/com/ureca/unity/global/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/ureca/unity/global/security/JwtAuthenticationFilter.java @@ -50,7 +50,6 @@ protected void doFilterInternal( String token = resolveToken(request); - // 1. 토큰이 아예 없는 경우 if (token == null) { request.setAttribute("authError", ErrorCode.TOKEN_MISSING); filterChain.doFilter(request, response); @@ -58,16 +57,11 @@ protected void doFilterInternal( } try { - // 2. 토큰 검증 시도 Authentication authentication = jwtProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); - } catch (ExpiredJwtException e) { - // 3. 토큰 만료 request.setAttribute("authError", ErrorCode.TOKEN_EXPIRED); - } catch (JwtException | IllegalArgumentException e) { - // 4. 토큰 위조 / 변조 request.setAttribute("authError", ErrorCode.INVALID_TOKEN); } diff --git a/src/main/java/com/ureca/unity/global/security/JwtProvider.java b/src/main/java/com/ureca/unity/global/security/JwtProvider.java index f36ff15..214d615 100644 --- a/src/main/java/com/ureca/unity/global/security/JwtProvider.java +++ b/src/main/java/com/ureca/unity/global/security/JwtProvider.java @@ -25,7 +25,6 @@ public JwtProvider(JwtProperties props) { ); } - /* JWT 검증 + userId(subject) 추출 */ public Long getUserId(String token, String expectedType) { Claims claims = Jwts.parser() .verifyWith(key) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a229daf..bcf0fe1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -62,7 +62,6 @@ oauth: kakao: client-id: ${KAKAO_CLIENT_ID} - # client-secret: "" token-uri: https://kauth.kakao.com/oauth/token user-info-uri: https://kapi.kakao.com/v2/user/me redirect-uri: ${KAKAO_REDIRECT_URI}