diff --git a/build.gradle b/build.gradle index 35f971f..ce43d26 100644 --- a/build.gradle +++ b/build.gradle @@ -33,26 +33,28 @@ repositories { } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-web' - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.h2database:h2' - runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.springframework.security:spring-security-test' - implementation("io.springfox:springfox-boot-starter:3.0.0") - implementation 'io.jsonwebtoken:jjwt-api:0.11.5' - implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' - implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' - implementation 'com.auth0:java-jwt:4.4.0' - implementation "com.googlecode.json-simple:json-simple:1.1.1" // Google Simple JSON - annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" - implementation 'org.springframework.boot:spring-boot-starter-validation:2.7.5' - implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" - annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.security:spring-security-test' + implementation("io.springfox:springfox-boot-starter:3.0.0") + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + implementation 'com.auth0:java-jwt:4.4.0' + implementation "com.googlecode.json-simple:json-simple:1.1.1" // Google Simple JSON + annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" + implementation 'org.springframework.boot:spring-boot-starter-validation:2.7.5' + implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" + annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" + + implementation 'com.google.api-client:google-api-client:1.30.10' } tasks.named('test') { diff --git a/src/main/java/com/milkcow/tripai/member/dto/GoogleDataDto.java b/src/main/java/com/milkcow/tripai/member/dto/GoogleDataDto.java deleted file mode 100644 index 63eec85..0000000 --- a/src/main/java/com/milkcow/tripai/member/dto/GoogleDataDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.milkcow.tripai.member.dto; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class GoogleDataDto { - private String nickname; - private String email; -} diff --git a/src/main/java/com/milkcow/tripai/member/service/OAuth2Service.java b/src/main/java/com/milkcow/tripai/member/service/OAuth2Service.java index e131924..a6f9fa6 100644 --- a/src/main/java/com/milkcow/tripai/member/service/OAuth2Service.java +++ b/src/main/java/com/milkcow/tripai/member/service/OAuth2Service.java @@ -1,30 +1,32 @@ package com.milkcow.tripai.member.service; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.Builder; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; import com.milkcow.tripai.global.dto.ResponseDto; import com.milkcow.tripai.global.exception.GeneralException; import com.milkcow.tripai.global.result.ApiResult; import com.milkcow.tripai.jwt.JwtService; import com.milkcow.tripai.member.domain.Member; -import com.milkcow.tripai.member.dto.GoogleDataDto; import com.milkcow.tripai.member.dto.MemberSignupRequestDto; import com.milkcow.tripai.member.exception.OAuth2Exception; import com.milkcow.tripai.member.repository.MemberRepository; import com.milkcow.tripai.member.result.OAuth2Result; import com.milkcow.tripai.security.MemberAdapter; -import java.util.Objects; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Collections; import java.util.Optional; import java.util.UUID; import javax.servlet.http.HttpServletResponse; +import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; @Service @RequiredArgsConstructor @@ -34,6 +36,14 @@ public class OAuth2Service { private final MemberRepository memberRepository; private final JwtService jwtService; private final MemberService memberService; + private static final NetHttpTransport transport = new NetHttpTransport(); + private static final JacksonFactory jsonFactory = new JacksonFactory(); + @Value("${OAuth2.Google-Client-Id}") + private String clientId; + private final GoogleIdTokenVerifier verifier = + new Builder(transport, jsonFactory) + .setAudience(Collections.singletonList(clientId)) + .build(); /** * google OAuth2 로그인 진행 회원가입 되어있지 않은 경우 회원가입 진행 @@ -41,8 +51,9 @@ public class OAuth2Service { * @param token (String, accessToken) * @param response (ResponseDto) */ + @Transactional public ResponseDto oAuth2Login(String token, HttpServletResponse response) { - GoogleDataDto googleData = getGoogleData(token); + GoogleData googleData = getGoogleDataFromToken(token); String email = googleData.getEmail(); Optional optionalMember = memberRepository.findByEmail(email); @@ -78,38 +89,39 @@ private void sendAccessAndRefreshToken(HttpServletResponse response, MemberAdapt } /** - * getGoogleData

프론트엔드로 부터 받은 Google OAuth2 access_token을 바탕으로 회원 정보 조회. + * 프론트엔드로 부터 받은 Google OAuth2 credential 바탕으로 회원 정보 추출 * - * @param token (프론트엔드로 부터 받은 Google OAuth2 access_token) + * @param token (프론트엔드로 부터 받은 Google OAuth2 credential) * @return GoogleDataDto */ - private GoogleDataDto getGoogleData(String token) { - try { - RestTemplate restTemplate = new RestTemplate(); - //구글에 정보 요청 - ResponseEntity responseEntity = restTemplate.getForEntity( - "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" - + token, - String.class - ); + private GoogleData getGoogleDataFromToken(String token) { + try{ +// GoogleIdToken idToken = verifier.verify(token); + GoogleIdToken idToken = GoogleIdToken.parse(new JacksonFactory(), token); - String responseBody = responseEntity.getBody(); - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode jsonNode = objectMapper.readTree(responseBody); - - //response body로 부터 정보 추출 - String nickname = jsonNode.get("name").asText(); - String email = jsonNode.get("email").asText(); - return new GoogleDataDto(nickname, email); - } catch (RestClientException e) { - //유효하지 않은 토큰의 경우 - if (Objects.requireNonNull(e.getMessage()).startsWith("401")) { + if(idToken == null){ throw new OAuth2Exception(OAuth2Result.INVALID_ACCESS_TOKEN); - } else { - throw new OAuth2Exception(OAuth2Result.FAIL_TO_ACCESS_GOOGLE_API); } - } catch (JsonProcessingException e) { + GoogleIdToken.Payload payload = idToken.getPayload(); + String nickname = (String) payload.get("name"); + String email = payload.getEmail(); + + return new GoogleData(email, nickname); + } catch (IOException e) { throw new GeneralException(ApiResult.INTERNAL_SERVER_ERROR); + } catch (IllegalArgumentException e){ + throw new OAuth2Exception(OAuth2Result.INVALID_ACCESS_TOKEN); + } + } + + @Data + private class GoogleData { + public String email; + public String nickname; + + public GoogleData(String email, String nickname) { + this.email = email; + this.nickname = nickname; } } } diff --git a/src/test/java/com/milkcow/tripai/member/service/OAuth2ServiceTest.java b/src/test/java/com/milkcow/tripai/member/service/OAuth2ServiceTest.java index 5d5284f..79f5193 100644 --- a/src/test/java/com/milkcow/tripai/member/service/OAuth2ServiceTest.java +++ b/src/test/java/com/milkcow/tripai/member/service/OAuth2ServiceTest.java @@ -28,9 +28,9 @@ class OAuth2ServiceTest { //when oAuth2Service.oAuth2Login(token, response); //then - Member member = memberRepository.findByEmail("junjuns1s1s@gmail.com").get(); + Member member = memberRepository.findByEmail("0902hdy@gmail.com").get(); System.out.println("member.getNickname() = " + member.getNickname()); - assertThat(member.getEmail()).isEqualTo("junjuns1s1s@gmail.com"); + assertThat(member.getEmail()).isEqualTo("0902hdy@gmail.com"); } @Test public void 구글_로그인() throws Exception{