#266 (인증): - AuthService.loginGoogle: catch-all에서 e.getMessage() 노출 → "Invalid Google token" 고정 메시지 + 상세는 log.warn (Google verifier 내부 오류 정보 누출 차단) #278 (지도): - boundsTimerRef 언마운트 cleanup (unmounted setState 경고 + 메모리 누수 방지) - '내 위치' 버튼 36×36 → 44×44 + aria-label='내 위치로 이동' + touch-manipulation - dead code 제거 (indexRef set-only, restaurantMap 미사용) #277 (health) — 결함 모두 후속 분리 (deep health, version, 테스트, rate limit) 후속 분리: - #338 (deep health/version/Actuator) - #339 (hex → brand-* 토큰 + 마커 ARIA + 테스트) - #340 (다중 audience verifier + AuthService 테스트) Refs: #266 #277 #278
80 lines
3.2 KiB
Java
80 lines
3.2 KiB
Java
package com.tasteby.service;
|
|
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
|
|
import com.google.api.client.http.javanet.NetHttpTransport;
|
|
import com.google.api.client.json.gson.GsonFactory;
|
|
import com.tasteby.domain.UserInfo;
|
|
import com.tasteby.security.JwtTokenProvider;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.web.server.ResponseStatusException;
|
|
|
|
import java.util.Collections;
|
|
import java.util.Map;
|
|
|
|
@Service
|
|
public class AuthService {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(AuthService.class);
|
|
|
|
private final UserService userService;
|
|
private final JwtTokenProvider jwtProvider;
|
|
private final GoogleIdTokenVerifier verifier;
|
|
|
|
public AuthService(UserService userService, JwtTokenProvider jwtProvider,
|
|
@Value("${app.google.client-id}") String googleClientId) {
|
|
this.userService = userService;
|
|
this.jwtProvider = jwtProvider;
|
|
this.verifier = new GoogleIdTokenVerifier.Builder(
|
|
new NetHttpTransport(), GsonFactory.getDefaultInstance())
|
|
.setAudience(Collections.singletonList(googleClientId))
|
|
.build();
|
|
}
|
|
|
|
public Map<String, Object> loginGoogle(String idTokenString) {
|
|
try {
|
|
GoogleIdToken idToken = verifier.verify(idTokenString);
|
|
if (idToken == null) {
|
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid Google token");
|
|
}
|
|
GoogleIdToken.Payload payload = idToken.getPayload();
|
|
|
|
UserInfo user = userService.findOrCreate(
|
|
"google",
|
|
payload.getSubject(),
|
|
payload.getEmail(),
|
|
(String) payload.get("name"),
|
|
(String) payload.get("picture"));
|
|
|
|
// Convert to Map for JWT
|
|
Map<String, Object> userMap = Map.of(
|
|
"id", user.getId(),
|
|
"email", user.getEmail() != null ? user.getEmail() : "",
|
|
"nickname", user.getNickname() != null ? user.getNickname() : "",
|
|
"is_admin", user.isAdmin()
|
|
);
|
|
String accessToken = jwtProvider.createToken(userMap);
|
|
return Map.of("access_token", accessToken, "user", user);
|
|
} catch (ResponseStatusException e) {
|
|
throw e;
|
|
} catch (Exception e) {
|
|
// #266 — 외부에는 고정 메시지만, 상세는 로그로 (Google verifier 내부 네트워크/공개키
|
|
// 조회 실패 메시지가 클라이언트에 노출되지 않도록)
|
|
log.warn("Google token verification failed: {}", e.getMessage());
|
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid Google token");
|
|
}
|
|
}
|
|
|
|
public UserInfo getCurrentUser(String userId) {
|
|
UserInfo user = userService.findById(userId);
|
|
if (user == null) {
|
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");
|
|
}
|
|
return user;
|
|
}
|
|
}
|