Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum ErrorCode {
USER_NOT_FOUND_BY_EMAIL(HttpStatus.NOT_FOUND, "ACCOUNT-002", "ํ•ด๋‹น ์ด๋ฉ”์ผ์˜ ํšŒ์›์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),
ACCOUNT_ALREADY_LINKED(HttpStatus.CONFLICT, "ACCOUNT-003", "์ด๋ฏธ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์™€ ์—ฐ๋™๋œ ์†Œ์…œ ๊ณ„์ •์ž…๋‹ˆ๋‹ค."),
SOCIAL_CONNECTION_NOT_FOUND(HttpStatus.NOT_FOUND, "ACCOUNT-004", "์—ฐ๋™๋œ ์†Œ์…œ ๊ณ„์ • ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),
USER_SETTING_NOT_FOUND_BY_ID(HttpStatus.NOT_FOUND, "ACCOUNT-005", "ํ•ด๋‹น ์•„์ด๋””์˜ ์„ค์ •์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),

// ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ด€๋ จ
OAUTH_PROCESSING_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "OAUTH-001", "์†Œ์…œ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."),
Expand All @@ -31,7 +32,7 @@ public enum ErrorCode {
OAUTH_COMMUNICATION_FAILED(HttpStatus.BAD_GATEWAY, "OAUTH-004", "์†Œ์…œ ํ”Œ๋žซํผ๊ณผ์˜ ํ†ต์‹ ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."),
SOCIAL_TOKEN_REFRESH_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "OAUTH-005", "์†Œ์…œ ํ”Œ๋žซํผ์˜ ํ† ํฐ ๊ฐฑ์‹ ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."),
SOCIAL_ACCOUNT_CONNECT_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "OAUTH-006", "์†Œ์…œ ๊ณ„์ • ์—ฐ๋™์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."),
GITHUB_TOKEN_REFRESH_NOT_SUPPORTED(HttpStatus.BAD_REQUEST, "OAUTH-007", "GitHub ํ† ํฐ ๊ฐฑ์‹ ์€ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์žฌ์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."),
SOCIAL_TOKEN_REFRESH_NOT_SUPPORTED(HttpStatus.BAD_REQUEST, "OAUTH-007", "๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ๊ฐฑ์‹ ์€ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์žฌ์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."),

// S3 ํŒŒ์ผ ๊ด€๋ จ
// Client Errors (4xx)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.teamEWSN.gitdeun.common.oauth.entity;
package com.teamEWSN.gitdeun.common.oauth.dto;

import com.teamEWSN.gitdeun.user.entity.Role;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.teamEWSN.gitdeun.common.oauth.dto;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class GitHubEmailDto {

private String email;
private boolean primary;
private boolean verified;
private String visibility;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.teamEWSN.gitdeun.common.oauth.entity;

import com.teamEWSN.gitdeun.common.converter.CryptoConverter;
import com.teamEWSN.gitdeun.common.util.BaseEntity;
import com.teamEWSN.gitdeun.common.util.AuditedEntity;
import com.teamEWSN.gitdeun.user.entity.User;
import jakarta.persistence.*;
import lombok.*;
Expand All @@ -10,7 +10,7 @@
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "social_connection")
public class SocialConnection extends BaseEntity {
public class SocialConnection extends AuditedEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
import com.teamEWSN.gitdeun.common.cookie.CookieUtil;
import com.teamEWSN.gitdeun.common.jwt.JwtToken;
import com.teamEWSN.gitdeun.common.jwt.JwtTokenProvider;
import com.teamEWSN.gitdeun.common.oauth.entity.CustomOAuth2User;
import com.teamEWSN.gitdeun.common.oauth.service.OAuthStateService;
import com.teamEWSN.gitdeun.user.service.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;

Expand All @@ -22,26 +24,31 @@
public class CustomOAuth2SuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

private final JwtTokenProvider jwtTokenProvider;
private final OAuthStateService oAuthStateService;
private final AuthService authService;
private final CookieUtil cookieUtil;

@Value("${app.front-url}")
private String frontUrl;

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {

// ์šฐ๋ฆฌ ์„œ๋น„์Šค์˜ JWT ์ƒ์„ฑ
OAuth2AuthenticationToken authToken = (OAuth2AuthenticationToken) authentication;
OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
String state = request.getParameter("state");

String purpose = oAuthStateService.consumeState(state); // "connect:42" ๋˜๋Š” null
if (purpose != null && purpose.startsWith("connect:")) {
Long userId = Long.parseLong(purpose.split(":")[1]);
authService.connectGithubAccount(oAuth2User, userId);
response.sendRedirect(frontUrl + "/oauth/callback#connected=true");
return;
}

// ์ผ๋ฐ˜ ๋กœ๊ทธ์ธ ํ๋ฆ„
JwtToken jwtToken = jwtTokenProvider.generateToken(authentication);
log.info("JWT๊ฐ€ ๋ฐœ๊ธ‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Access Token: {}", jwtToken.getAccessToken());

// Refresh Token์€ HttpOnly ์ฟ ํ‚ค์— ์ €์žฅ
cookieUtil.setCookie(response, "refreshToken", jwtToken.getRefreshToken(), jwtTokenProvider.getRefreshTokenExpired());

// Access Token์€ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ”„๋ก ํŠธ์—”๋“œ์— ์ „๋‹ฌ
String targetUrl = UriComponentsBuilder.fromUriString(frontUrl + "/oauth/callback")
.queryParam("accessToken", jwtToken.getAccessToken())
.build().toUriString();

String targetUrl = frontUrl + "/oauth/callback#accessToken=" + jwtToken.getAccessToken();
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.teamEWSN.gitdeun.common.oauth.record;

import com.fasterxml.jackson.annotation.JsonProperty;

public record GoogleTokenResponse(
@JsonProperty("access_token") String accessToken,
@JsonProperty("refresh_token") String refreshToken,
@JsonProperty("token_type") String tokenType,
@JsonProperty("expires_in") Long expiresIn,
@JsonProperty("scope") String scope,
@JsonProperty("id_token") String idToken
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.teamEWSN.gitdeun.common.exception.GlobalException;
import com.teamEWSN.gitdeun.common.exception.ErrorCode;
import com.teamEWSN.gitdeun.common.oauth.dto.GitHubEmailDto;
import com.teamEWSN.gitdeun.common.oauth.dto.provider.GitHubResponseDto;
import com.teamEWSN.gitdeun.common.oauth.dto.provider.GoogleResponseDto;
import com.teamEWSN.gitdeun.common.oauth.dto.provider.OAuth2ResponseDto;
Expand All @@ -11,7 +12,7 @@
import com.teamEWSN.gitdeun.user.entity.User;
import com.teamEWSN.gitdeun.common.oauth.repository.SocialConnectionRepository;
import com.teamEWSN.gitdeun.user.repository.UserRepository;
import com.teamEWSN.gitdeun.common.oauth.entity.CustomOAuth2User;
import com.teamEWSN.gitdeun.common.oauth.dto.CustomOAuth2User;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -21,6 +22,8 @@
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.UUID;


Expand All @@ -29,6 +32,8 @@
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

private final GitHubApiHelper gitHubApiHelper;
private final SocialTokenRefreshService socialTokenRefreshService;
private final UserRepository userRepository;
private final SocialConnectionRepository socialConnectionRepository;

Expand All @@ -44,61 +49,68 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
throw new GlobalException(ErrorCode.OAUTH_COMMUNICATION_FAILED);
}

User user = processUserInTransaction(oAuth2User, userRequest);
User user = processUser(oAuth2User, userRequest);
return new CustomOAuth2User(user.getId(), user.getRole());
}

// @Transactional
public User processUserInTransaction(OAuth2User oAuth2User, OAuth2UserRequest userRequest) {
OAuth2ResponseDto oAuth2ResponseDto = getOAuth2ResponseDto(oAuth2User, userRequest);

// ์ด๋ฉ”์ผ ์ •๋ณด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ (GitHub ๋“ฑ)
if (oAuth2ResponseDto.getEmail() == null) {
throw new GlobalException(ErrorCode.EMAIL_NOT_PROVIDED);
}

OauthProvider provider = OauthProvider.valueOf(oAuth2ResponseDto.getProvider().toUpperCase());
String providerId = oAuth2ResponseDto.getProviderId();
String accessToken = userRequest.getAccessToken().getTokenValue();
public User processUser(OAuth2User oAuth2User, OAuth2UserRequest userRequest) {
OAuth2ResponseDto dto = getOAuth2ResponseDto(oAuth2User, userRequest);
OauthProvider provider = OauthProvider.valueOf(dto.getProvider().toUpperCase());
String providerId = dto.getProviderId();
String accessToken = userRequest.getAccessToken().getTokenValue();
String refreshToken = (String) userRequest.getAdditionalParameters().get("refresh_token");

/* โ‘ก ์ด๋ฏธ ์—ฐ๊ฒฐ๋œ ๊ณ„์ • โ†’ ํ† ํฐ ๊ฐฑ์‹  ๋กœ์ง ์ถ”์ƒํ™” */
return socialConnectionRepository.findByProviderAndProviderId(provider, providerId)
.map(connection -> {
log.info("๊ธฐ์กด ์†Œ์…œ ๊ณ„์ • ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค: {}", provider);
connection.updateTokens(accessToken, refreshToken);
return connection.getUser();
.map(conn -> {
// provider ๋ณ„ refresh ์ •์ฑ…
socialTokenRefreshService.refreshSocialToken(conn, accessToken, refreshToken);
return conn.getUser();
})
.orElseGet(() -> {
// ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ ํ•ด๋‹น ์ด๋ฉ”์ผ์„ ์‚ฌ์šฉ ์ค‘์ธ์ง€ ํ™•์ธ
userRepository.findByEmailAndDeletedAtIsNull(oAuth2ResponseDto.getEmail())
.ifPresent(existingUser -> {
// ์ด๋ฉ”์ผ์€ ๊ฐ™์ง€๋งŒ, ์†Œ์…œ ์—ฐ๋™ ์ •๋ณด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ -> ๊ณ„์ • ์—ฐ๋™
log.info("๊ธฐ์กด ํšŒ์› ๊ณ„์ •์— ์†Œ์…œ ๊ณ„์ •์„ ์—ฐ๋™ํ•ฉ๋‹ˆ๋‹ค: {}", provider);
connectSocialAccount(existingUser, provider, providerId, accessToken, refreshToken);
});
// ์œ„์—์„œ ์—ฐ๋™ํ–ˆ๊ฑฐ๋‚˜, ์™„์ „ ์‹ ๊ทœ ์œ ์ €์ธ ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌ
// ๋‹ค์‹œ ์ด๋ฉ”์ผ๋กœ ์กฐํšŒํ•˜์—ฌ ์ตœ์ข… ์œ ์ €๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ ์ƒ์„ฑ
return userRepository.findByEmailAndDeletedAtIsNull(oAuth2ResponseDto.getEmail())
.orElseGet(() -> {
log.info("์‹ ๊ทœ ํšŒ์› ๋ฐ ์†Œ์…œ ๊ณ„์ •์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค: {}", provider);
return createNewUser(oAuth2ResponseDto, provider, providerId, accessToken, refreshToken);
});
});
.orElseGet(() -> createOrConnect(dto, provider, providerId, accessToken, refreshToken));
}

private static OAuth2ResponseDto getOAuth2ResponseDto(OAuth2User oAuth2User, OAuth2UserRequest userRequest) {
// OAuth2 ๊ณต๊ธ‰์ž๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ OAuth2ResponseDto๋ฅผ ์ƒ์„ฑ(์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ)
private OAuth2ResponseDto getOAuth2ResponseDto(OAuth2User oAuth2User, OAuth2UserRequest userRequest) {
String registrationId = userRequest.getClientRegistration().getRegistrationId();
Map<String, Object> attr = oAuth2User.getAttributes();

OAuth2ResponseDto oAuth2ResponseDto;
if (registrationId.equalsIgnoreCase("google")) {
oAuth2ResponseDto = new GoogleResponseDto(oAuth2User.getAttributes());
} else if (registrationId.equalsIgnoreCase("github")) {
oAuth2ResponseDto = new GitHubResponseDto(oAuth2User.getAttributes());
return new GoogleResponseDto(attr);
}
if (registrationId.equalsIgnoreCase("github")) {
/* โ‘  ๊ธฐ๋ณธ ํ”„๋กœํ•„์— e-mail ์—†์œผ๋ฉด /user/emails ํ˜ธ์ถœ */
if (attr.get("email") == null) {
// accessToken ์œผ๋กœ GitHub ๋ณด์กฐ API ํ˜ธ์ถœ
List<GitHubEmailDto> emails =
gitHubApiHelper.getPrimaryEmails(userRequest.getAccessToken().getTokenValue());
attr.put("email",
emails.stream().filter(GitHubEmailDto::isPrimary)
.findFirst().map(GitHubEmailDto::getEmail).orElse(null));
}
return new GitHubResponseDto(attr);
} else {
// ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ์ œ๊ณต์ž
throw new GlobalException(ErrorCode.UNSUPPORTED_OAUTH_PROVIDER);
}
return oAuth2ResponseDto;
}

/**
* ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜๋ฉด ๊ณ„์ •์„ ์—ฐ๊ฒฐํ•˜๊ณ , ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
*/
private User createOrConnect(OAuth2ResponseDto response, OauthProvider provider, String providerId, String accessToken, String refreshToken) {
// ์ด๋ฉ”์ผ๋กœ ๊ธฐ์กด ์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
return userRepository.findByEmailAndDeletedAtIsNull(response.getEmail())
.map(user -> {
// ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜๋ฉด, ์ƒˆ ์†Œ์…œ ๊ณ„์ •์„ ์—ฐ๊ฒฐ
connectSocialAccount(user, provider, providerId, accessToken, refreshToken);
return user;
})
.orElseGet(() -> {
// ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด, ์ƒˆ ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑ
return createNewUser(response, provider, providerId, accessToken, refreshToken);
});
}

private User createNewUser(OAuth2ResponseDto response, OauthProvider provider, String providerId, String accessToken, String refreshToken) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@

import com.teamEWSN.gitdeun.common.exception.ErrorCode;
import com.teamEWSN.gitdeun.common.exception.GlobalException;
import com.teamEWSN.gitdeun.common.oauth.dto.provider.GitHubResponseDto;
import com.teamEWSN.gitdeun.common.oauth.dto.GitHubEmailDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;

@Slf4j
Expand All @@ -32,60 +31,28 @@ public class GitHubApiHelper {
@Value("${spring.security.oauth2.client.registration.github.client-secret}")
private String clientSecret;

@Value("${spring.security.oauth2.client.registration.github.redirect-uri}")
private String redirectUri;

/**
* ์ธ๊ฐ€ ์ฝ”๋“œ๋กœ GitHub Access Token์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
* @param code GitHub์—์„œ ๋ฐ›์€ ์ธ๊ฐ€ ์ฝ”๋“œ
* @return Access Token ๋ฌธ์ž์—ด
*/
public String getAccessToken(String code) {
String tokenUri = "https://github.com/login/oauth/access_token";

MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("client_id", clientId);
formData.add("client_secret", clientSecret);
formData.add("code", code);
formData.add("redirect_uri", redirectUri);

Map<String, Object> response = webClient.post()
.uri(tokenUri)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(formData)
.retrieve()
// ๋‹จ์ˆœ map์ด ์•„๋‹Œ ์ •ํ™•ํ•œ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋Ÿฐํƒ€์ž„์—๋„ ์žƒ์–ด๋ฒ„๋ฆฌ์ง€ ์•Š๋„๋ก ParameterizedTypeReference๋ฅผ ์‚ฌ์šฉ
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
.block();

if (response == null || response.get("access_token") == null) {
log.error("GitHub Access Token ๋ฐœ๊ธ‰ ์‹คํŒจ: {}", response);
throw new GlobalException(ErrorCode.OAUTH_PROCESSING_ERROR);
}

return (String) response.get("access_token");
}

/**
* Access Token์œผ๋กœ GitHub ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
* Access Token์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
* GitHub ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ •๋ณด์— ์ด๋ฉ”์ผ์ด ํฌํ•จ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
* @param accessToken GitHub Access Token
* @return GitHub ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ด์€ DTO
* @return ์ด๋ฉ”์ผ ์ •๋ณด DTO ๋ฆฌ์ŠคํŠธ
*/
public GitHubResponseDto getUserInfo(String accessToken) {
String userInfoUri = "https://api.github.com/user";
public List<GitHubEmailDto> getPrimaryEmails(String accessToken) {
String emailsUri = "https://api.github.com/user/emails";

Map<String, Object> attributes = webClient.get()
.uri(userInfoUri)
.header(HttpHeaders.AUTHORIZATION, "token " + accessToken)
List<GitHubEmailDto> emails = webClient.get()
.uri(emailsUri)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
.bodyToMono(new ParameterizedTypeReference<List<GitHubEmailDto>>() {})
.block();

if (attributes == null) {
if (emails == null || emails.isEmpty()) {
log.error("GitHub ์ด๋ฉ”์ผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
throw new GlobalException(ErrorCode.OAUTH_COMMUNICATION_FAILED);
}

return new GitHubResponseDto(attributes);
return emails;
}


Expand Down
Loading