📝오늘 공부한 것
- 실전 프로젝트 - '행동대장' 카카오로그인 기능구현
⛔문제점 ①
카카오 로그인 시 개인정보 동의에서 이메일제공에 동의하지 않는 유저가 있을 경우
[에러메시지]
ERROR 34868 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "com.fasterxml.jackson.databind.JsonNode.asText()" because the return value of "com.fasterxml.jackson.databind.JsonNode.get(String)" is null] with root cause java.lang.NullPointerException: Cannot invoke "com.fasterxml.jackson.databind.JsonNode.asText()" because the return value of "com.fasterxml.jackson.databind.JsonNode.get(String)" is null
우리 프로젝트는 이메일로 로그인을 진행한다. 그래서 이메일이 로직에서 많이 사용된다.
그런데!!카카오로그인 기능을 구현하고 보니까 카카오회원가입 시 이메일 제공에 선택을 하지 않으면 이메일에 대한 정보를 저장할 수 없는 것이었다!!그래서 이메일 제공에 선택을 하지 않으면, 서버에서 카카오로 없는 정보를 가져오려고 하기 때문에 nullpointerexception이 나는 것이었다.
⛔문제점 ②
기존에 일반회원으로 가입한 유저와의 닉네임 중복 문제
일반회원으로 가입한 유저는 닉네임 중복확인을 진행한 뒤 회원가입이 진행된다. 그런데 카카오로그인으로 회원가입을 하는 경우 카카오에 저장된 닉네임이 서버로 들어오는 것이기 때문에 중복체크를 진행할 수 없다.
💯해결
이메일이 필수 선택이라면 바로 해결되는 문제였지만..
동의항목설정 시 이메일은 필수동의로 할 수 없었다ㅠㅠ
그래서 이메일을 제공하지 않는 사람을 null로 저장하고 있는 사람만 이메일을 받아오도록 구현하였다.
✔ KakaoService
private KakaoUserInfoDto getKakaoUserInfo(String accessToken) throws JsonProcessingException {
log.info("accessToken : " + accessToken);
// 요청 URL 만들기
URI uri = UriComponentsBuilder
.fromUriString("https://kapi.kakao.com")
.path("/v2/user/me")
.encode()
.build()
.toUri();
// HTTP Header 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
RequestEntity<MultiValueMap<String, String>> requestEntity = RequestEntity
.post(uri)
.headers(headers)
.body(new LinkedMultiValueMap<>());
// HTTP 요청 보내기
ResponseEntity<String> response = restTemplate.exchange(
requestEntity,
String.class
);
JsonNode jsonNode = new ObjectMapper().readTree(response.getBody());
Long id = jsonNode.get("id").asLong();
String nickname = jsonNode.get("properties")
.get("nickname").asText();
JsonNode kakaoAccountNode = jsonNode.get("kakao_account");
String email = null;
if (kakaoAccountNode != null && kakaoAccountNode.has("email")) {
email = kakaoAccountNode.get("email").asText();
return new KakaoUserInfoDto(id, nickname, email);
} else {
return new KakaoUserInfoDto(id, nickname);
}
}
카카오로그인을 진행하는 부분에서는 이렇게 코드를 작성하기로 했다.
또, 카카오로 회원가입을 진행하는 경우에는
카카오에서 들어오는 닉네임 + _KAKAO + kakaoId로 닉네임을 설정하여 중복문제를 해결하였다.
//닉네임 = 닉네임 + _KAKAO + kakaoId
String nickname = kakaoUserInfo.getNickname() + "_KAKAO" + kakaoId;
✔ KakaoService
private User registerKakaoUserIfNeeded(KakaoUserInfoDto kakaoUserInfo) {
Long kakaoId = kakaoUserInfo.getId();
User kakaoUser = userRepository.findByKakaoId(kakaoId).orElse(null);
if (kakaoUser == null) {
String nickname = kakaoUserInfo.getNickname() + "_KAKAO" + kakaoId;
String password = UUID.randomUUID().toString();
String encodedPassword = passwordEncoder.encode(password);
String kakaoEmail = kakaoUserInfo.getEmail();
if(kakaoEmail != null){
User sameEmailUser = userRepository.findByEmail(kakaoEmail).orElse(null);
if (sameEmailUser != null) {
kakaoUser = sameEmailUser;
kakaoUser = kakaoUser.kakaoIdUpdate(kakaoId);
} else {
String email = kakaoUserInfo.getEmail();
kakaoUser = new User(nickname, encodedPassword, email, UserRoleEnum.USER, kakaoId);
}
userRepository.save(kakaoUser);
} else {
kakaoUser = new User(nickname, encodedPassword, UserRoleEnum.USER, kakaoId);
userRepository.save(kakaoUser);
}
}
return kakaoUser;
}
느낀 점🤔
소셜로그인을 진행하기로 했을때부터 잘 알아봤어야 하는건데 이미 기능구현을 완료하고 나서 발견했던 것이라 많이 아쉬웠다ㅠㅠ 앞으로 충분히 조사를 하고 어떤 식으로 코드를 작성해야할지 정리를 한후에 진행해야겠다.
'TIL(Today I Learned)' 카테고리의 다른 글
TIL-230830(항해99 실전 프로젝트-행동대장(20)) (0) | 2023.08.30 |
---|---|
TIL-230829(항해99 실전 프로젝트-행동대장(19)) (0) | 2023.08.29 |
TIL-230826(항해99 실전 프로젝트-행동대장(17)) (0) | 2023.08.26 |
TIL-230825(항해99 실전 프로젝트-행동대장(16), EC2에 Swap Memory 적용) (0) | 2023.08.25 |
TIL-230824(항해99 실전 프로젝트-행동대장(15)) (0) | 2023.08.25 |