From 1e1b6bbc550aa5a7d1e29e4ffd7106dadce34357 Mon Sep 17 00:00:00 2001 From: daeunkwak Date: Sun, 17 Sep 2023 18:24:35 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EA=B5=AC=EA=B8=80=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20idToken=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 21 +++- .../please/api/OauthLoginController.java | 4 +- .../service/google/GoogleDriveService.java | 4 +- .../service/oauth/OauthLoginService.java | 96 +++++++++++++++++++ 4 files changed, 116 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 1eed80b..298199c 100644 --- a/build.gradle +++ b/build.gradle @@ -56,16 +56,27 @@ dependencies { // image metadata implementation 'com.drewnoakes:metadata-extractor:2.9.1' + // gson + // implementation 'com.google.code.gson:gson:2.8.8' + implementation 'com.google.api-client:google-api-client-gson:1.35.1' + + // json + implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4' + // gdrive - // implementation 'com.google.api-client:google-api-client:1.30.9' + //implementation 'com.google.api-client:google-api-client:1.30.9' //implementation 'com.google.oauth-client:google-oauth-client-jetty:RELEASE' + + // implementation 'com.google.api-client:google-api-client:1.31.1' implementation 'com.google.oauth-client:google-oauth-client-jetty:1.31.1' - implementation 'com.google.apis:google-api-services-drive:v2-rev20220815-2.0.0' +// implementation 'com.google.apis:google-api-services-drive:v2-rev20220815-2.0.0' +// +// implementation 'com.fasterxml.jackson.core:jackson-core:2.12.4' +// implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4' +// implementation 'com.fasterxml.jackson.core:jackson-annotations:2.12.4' + /// - implementation 'com.fasterxml.jackson.core:jackson-core:2.12.4' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.12.4' // map //implementation 'org.springframework.cloud:spring-cloud-starter-gcp' diff --git a/src/main/java/app/gangdan/please/api/OauthLoginController.java b/src/main/java/app/gangdan/please/api/OauthLoginController.java index a9de474..3fb77e8 100644 --- a/src/main/java/app/gangdan/please/api/OauthLoginController.java +++ b/src/main/java/app/gangdan/please/api/OauthLoginController.java @@ -27,7 +27,7 @@ public class OauthLoginController { @Tag(name = "oauth") @PostMapping(value = "/login", headers = {"Content-type=application/json"}, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "OAuth 로그인 API", description = "Authorization code로 로그인 시 JWT 토큰 반환, 현재 GOOGLE만 지원") + @Operation(summary = "OAuth 로그인 API") public ResponseEntity loginOauth(HttpServletRequest httpServletRequest) { log.info("=== Oauth login start ==="); @@ -39,7 +39,7 @@ public ResponseEntity loginOauth(HttpServletRequest httpSer final SocialType socialType = SocialType.GOOGLE; - final ResponseJwtTokenDto jwtTokenDto = oauthLoginService.login(socialType, httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION)); + final ResponseJwtTokenDto jwtTokenDto = oauthLoginService.googleLoginV2(httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION)); log.info("=== Oauth login end ==="); return ResponseEntity.ok(jwtTokenDto); diff --git a/src/main/java/app/gangdan/please/service/google/GoogleDriveService.java b/src/main/java/app/gangdan/please/service/google/GoogleDriveService.java index ab12115..f7ef5c0 100644 --- a/src/main/java/app/gangdan/please/service/google/GoogleDriveService.java +++ b/src/main/java/app/gangdan/please/service/google/GoogleDriveService.java @@ -1,6 +1,6 @@ package app.gangdan.please.service.google; -import com.google.api.services.drive.Drive; -import com.google.api.services.drive.model.File; +//import com.google.api.services.drive.Drive; +//import com.google.api.services.drive.model.File; import com.google.api.client.http.FileContent; import org.springframework.web.multipart.MultipartFile; diff --git a/src/main/java/app/gangdan/please/service/oauth/OauthLoginService.java b/src/main/java/app/gangdan/please/service/oauth/OauthLoginService.java index f5dfb3f..ffc0e95 100644 --- a/src/main/java/app/gangdan/please/service/oauth/OauthLoginService.java +++ b/src/main/java/app/gangdan/please/service/oauth/OauthLoginService.java @@ -9,19 +9,29 @@ import app.gangdan.please.dto.member.jwt.TokenDto; import app.gangdan.please.dto.oauth.OAuthAttributes; import app.gangdan.please.dto.oauth.OauthLoginDto; +import app.gangdan.please.global.exception.BadRequestException; import app.gangdan.please.global.exception.MemberTokenNotFoundException; import app.gangdan.please.service.jwt.TokenProvider; import app.gangdan.please.service.oauth.google.GoogleFeignService; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.http.apache.v2.ApacheHttpTransport; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.google.api.client.json.gson.GsonFactory; +import com.google.api.client.json.*; +import java.io.IOException; +import java.security.GeneralSecurityException; import java.security.InvalidParameterException; import java.time.LocalDateTime; +import java.util.Collections; import java.util.Optional; @Slf4j @@ -36,6 +46,92 @@ public class OauthLoginService { private final MemberRepository memberRepository; private final MemberTokenRepository memberTokenRepository; + @Value("${oauth2.clientId}") + private String CLIENT_ID; + + public ResponseJwtTokenDto googleLoginV2(String tokenString) { + + Member requestMember; + GoogleIdToken idToken = getVerifiedIdToken(tokenString); + + if (idToken == null) { + throw new BadRequestException("Invalid token"); + } + + GoogleIdToken.Payload payload = idToken.getPayload(); + + // Get profile information from payload + String email = payload.getEmail(); + + OAuthAttributes socialUserInfo = generateSocialInfoFromIdToken(idToken); + + log.info("oauthAttributes: {}", socialUserInfo.toString()); + + final Optional foundMember = memberRepository.findByEmail(email); + + if (foundMember.isEmpty()) { // 기존 회원 아닐 때 + Member newMember = Member.create(socialUserInfo); + requestMember = memberRepository.save(newMember); + } else { + requestMember = foundMember.get(); // 기존 회원일 때 + } + + // JWT 토큰 생성 + ResponseJwtTokenDto responseJwtTokenDto = generateToken(requestMember); + + return responseJwtTokenDto; + } + + public GoogleIdToken getVerifiedIdToken(String idTokenString) { + GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier + .Builder( + new ApacheHttpTransport(ApacheHttpTransport.newDefaultHttpClient()), + new GsonFactory() + ) + .setAudience(Collections.singletonList(CLIENT_ID)) + .setIssuer("https://accounts.google.com") + .build(); + try { + return verifier.verify(idTokenString); + } catch (GeneralSecurityException | IOException e) { + return null; + } + } + + public OAuthAttributes generateSocialInfoFromIdToken(GoogleIdToken idToken) { + GoogleIdToken.Payload payload = idToken.getPayload(); + + // Print user identifier + String userId = payload.getSubject(); + + // Get profile information from payload + String email = payload.getEmail(); + String name = (String) payload.get("name"); + + return OAuthAttributes + .builder() + .email(StringUtils.isBlank(email) ? userId : email) // 이메일 동의 x 경우 + .name(name) + .socialType(SocialType.GOOGLE) + .build(); + } + + public ResponseJwtTokenDto generateToken(Member member) { + // JWT 토큰 생성 + TokenDto tokenDto = tokenProvider.createTokenDto(member.getMemberId()); + log.info("tokenDto: {}", tokenDto); + + ResponseJwtTokenDto responseJwtTokenDto = modelMapper.map(tokenDto, ResponseJwtTokenDto.class); + final boolean isNewMember = StringUtils.isEmpty(member.getUsername()); + responseJwtTokenDto.setIsNewMember(isNewMember); + if (!isNewMember) { + responseJwtTokenDto.setMemberName(member.getUsername()); + } + responseJwtTokenDto.setMemberId(member.getMemberId()); + + return responseJwtTokenDto; + } + // 7 public ResponseJwtTokenDto createMemberAndJwt(OauthLoginDto oauthLoginDto) {