Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 구글 로그인 accessToken이 아닌 credentials로 접근하도록 수정 #23

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down
11 changes: 0 additions & 11 deletions src/main/java/com/milkcow/tripai/member/dto/GoogleDataDto.java

This file was deleted.

80 changes: 46 additions & 34 deletions src/main/java/com/milkcow/tripai/member/service/OAuth2Service.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -34,15 +36,24 @@ 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 로그인 진행 회원가입 되어있지 않은 경우 회원가입 진행
*
* @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<Member> optionalMember = memberRepository.findByEmail(email);

Expand Down Expand Up @@ -78,38 +89,39 @@ private void sendAccessAndRefreshToken(HttpServletResponse response, MemberAdapt
}

/**
* getGoogleData<p> 프론트엔드로 부터 받은 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<String> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down