우리는 메일이 꼭 필요하다.. 꼭 구현해내리라
Github 계정 - Settings - Email 탭
에서 Primary 이메일이 없거나,
private 설정이 되어있으면 이메일을 가져올 수가 없는 것 같다!
깃허브로부터 발급받은 accessToken
을 이용해서 유저 정보를 가져올 수 있다.
https://api.github.com/user/emails
- Header Authorization Bearer USER_TOKEN
이메일 가져오는 API를 한번 더 호출하는 것이다!
// OAuth2UserRequest에서 accessToken 가져오기
String accessToken = userRequest.getAccessToken().getTokenValue();
// 이메일 가져오는 메서드
public String getEmail() {
try {
String attributeEmail = (String) attributes.get("email");
return attributeEmail != null ? attributeEmail : fetchEmailWithAccessToken(accessToken);
} catch (Exception e){
throw new OAuth2Exception(OAuth2ExceptionCode.SOCIAL_EMAIL_NOT_FOUND);
}
}
/**
* public 이메일이 없을 경우, accessToken을 사용하여 이메일을 반환하는 메서드
* @param accessToken 사용자 액세스 토큰
* @return private 사용자 이메일을 반환
*/
private String fetchEmailWithAccessToken(String accessToken) {
WebClient webClient = WebClient.builder()
.baseUrl("https://api.github.com")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.defaultHeader(HttpHeaders.ACCEPT, "application/vnd.github.v3+json")
.build();
List<Map<String, Object>> emails = webClient.get()
.uri("/user/emails")
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<Map<String, Object>>>() {})
.block();
if (emails != null) {
for (Map<String, Object> emailEntry : emails) {
if (Boolean.TRUE.equals(emailEntry.get("primary")) && Boolean.TRUE.equals(emailEntry.get("verified"))) {
return (String) emailEntry.get("email");
}
}
}
throw new OAuth2Exception(OAuth2ExceptionCode.SOCIAL_EMAIL_NOT_FOUND_WITH_TOKEN);
}
fetchEmailWithAccessToken()
메서드를 실행한다.❓ WebClient
- 스프링에서 제공하는 HTTP 요청을 만드는 라이브러리
- 반응형(Reactive)으로 설계되어 있어 비동기(Async), 비차단(Non-Blocking) 통신을 효율적으로 처리할 수 있다고 한다.
https://uhanuu.tistory.com/entry/OAuth-20-GitHub-이메일-null이슈
https://vesselsdiary.tistory.com/192
https://github.com/nextauthjs/next-auth/issues/374