Skip to content

Commit

Permalink
✨ Feature: 구글 로그인 기능 구현 (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahnsugyeong authored May 31, 2024
1 parent 7510ea3 commit c9eb3c0
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import zzangdol.jwt.JwtResponse;
import zzangdol.jwt.JwtService;
import zzangdol.oauth.client.SocialLoginClient;
import zzangdol.oauth.dto.GoogleUserInfoResponse;
import zzangdol.oauth.dto.KakaoUserInfoResponse;
import zzangdol.oauth.dto.SocialUserInfoResponse;
import zzangdol.response.status.ErrorStatus;
Expand All @@ -35,13 +36,18 @@ public class AuthService {

private static final int RANDOM_PASSWORD_LENGTH = 10;

public AuthService(PasswordEncoder passwordEncoder, UserRepository userRepository, JwtService jwtService,
SocialLoginClient<KakaoUserInfoResponse> kakaoLoginClient /*, SocialLoginClient<NaverUserInfoResponse> naverLoginClient */) {
public AuthService(PasswordEncoder passwordEncoder,
UserRepository userRepository,
JwtService jwtService,
SocialLoginClient<KakaoUserInfoResponse> kakaoLoginClient,
SocialLoginClient<GoogleUserInfoResponse> googleLoginClient
/*, SocialLoginClient<NaverUserInfoResponse> naverLoginClient */) {
this.passwordEncoder = passwordEncoder;
this.userRepository = userRepository;
this.jwtService = jwtService;
this.socialLoginClients = new EnumMap<>(AuthProvider.class);
this.socialLoginClients.put(AuthProvider.KAKAO, kakaoLoginClient);
this.socialLoginClients.put(AuthProvider.GOOGLE, googleLoginClient);
// this.socialLoginClients.put(AuthProvider.NAVER, naverLoginClient);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package zzangdol.user.domain;

public enum AuthProvider {
KAKAO, NAVER, APPLE, DEFAULT
KAKAO, GOOGLE, NAVER, APPLE, DEFAULT
}
2 changes: 2 additions & 0 deletions moodoodle-domain/src/main/java/zzangdol/user/domain/User.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package zzangdol.user.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
Expand Down Expand Up @@ -33,6 +34,7 @@ public class User extends BaseTimeEntity implements UserDetails {
private LocalTime notificationTime;
private Boolean isRead;

@Column(nullable = false, length = 50)
@Enumerated(EnumType.STRING)
private AuthProvider authProvider;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package zzangdol.oauth.client.google;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import zzangdol.oauth.client.SocialLoginClient;
import zzangdol.oauth.dto.GoogleTokenResponse;
import zzangdol.oauth.dto.GoogleUserInfoResponse;

@RequiredArgsConstructor
@Service
public class GoogleLoginClient implements SocialLoginClient<GoogleUserInfoResponse> {

private final GoogleLoginTokenClient googleLoginTokenClient;
private final GoogleLoginUserClient googleLoginUserClient;

@Override
public GoogleUserInfoResponse getUserInfo(String authorizationCode) {
GoogleTokenResponse tokenInfo = googleLoginTokenClient.getTokenInfo(authorizationCode);
return googleLoginUserClient.getUserInfo(tokenInfo.getAccessToken());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package zzangdol.oauth.client.google;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import zzangdol.oauth.dto.GoogleTokenResponse;

@Slf4j
@Component
public class GoogleLoginTokenClient {

private WebClient webClient;

@Value("${google.token.uri}")
private String TOKEN_URI;

@Value("${google.redirect.uri}")
private String REDIRECT_URI;

@Value("${google.grant.type}")
private String GRANT_TYPE;

@Value("${google.client.id}")
private String CLIENT_ID;

@Value("${google.client.secret}")
private String CLIENT_SECRET;

@Value("${google.scope}")
private String SCOPE;

@Value("${google.response_type}")
private String RESPONSE_TYPE;

@PostConstruct
private void init() {
this.webClient = WebClient.builder()
.baseUrl(TOKEN_URI)
.build();
}

public GoogleTokenResponse getTokenInfo(final String code) {
log.info("Requesting token with code: {}", code);

return webClient.post()
.uri("")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData("grant_type", GRANT_TYPE)
.with("client_id", CLIENT_ID)
.with("redirect_uri", REDIRECT_URI)
.with("code", code)
.with("client_secret", CLIENT_SECRET))
.retrieve()
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), clientResponse -> clientResponse.bodyToMono(String.class)
.flatMap(response -> {
log.error("Error Response: {}", response);
return Mono.error(new RuntimeException("Error Response: " + response));
}))
.bodyToMono(GoogleTokenResponse.class)
.block();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package zzangdol.oauth.client.google;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import zzangdol.oauth.dto.GoogleUserInfoResponse;

@Slf4j
@Component
public class GoogleLoginUserClient {

private final WebClient webClient;

private static final String USER_INFO_URI = "https://www.googleapis.com/oauth2/v3/userinfo";

public GoogleLoginUserClient() {
this.webClient = WebClient.builder()
.baseUrl(USER_INFO_URI)
.build();
}

public GoogleUserInfoResponse getUserInfo(final String token) {
return webClient.get()
.uri("")
.header("Authorization", "Bearer " + token)
.retrieve()
.bodyToMono(GoogleUserInfoResponse.class)
.block();
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package zzangdol.oauth.client;
package zzangdol.oauth.client.kakao;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import zzangdol.oauth.client.SocialLoginClient;
import zzangdol.oauth.dto.KakaoTokenResponse;
import zzangdol.oauth.dto.KakaoUserInfoResponse;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package zzangdol.oauth.client;
package zzangdol.oauth.client.kakao;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package zzangdol.oauth.client;
package zzangdol.oauth.client.kakao;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package zzangdol.oauth.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class GoogleTokenResponse {

private String accessToken;
private int expiresIn;
private String refreshToken;
private String scope;
private String tokenType;
private String idToken;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package zzangdol.oauth.dto;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class GoogleUserInfoResponse implements SocialUserInfoResponse {

private String email;
private String name;

@Override
public String getEmail() {
return this.email;
}

@Override
public String getNickname() {
return this.name;
}
}

0 comments on commit c9eb3c0

Please sign in to comment.