본문 바로가기

TIL(Today I Learned)

TIL-230828(항해99 실전 프로젝트-행동대장(18))

📝오늘 공부한 것

  • 실전 프로젝트 - '행동대장' 카카오로그인 기능구현

 

⛔문제점 ①

카카오 로그인 시 개인정보 동의에서 이메일제공에 동의하지 않는 유저가 있을 경우

 

[에러메시지]

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;
    }

 

 

느낀 점🤔

소셜로그인을 진행하기로 했을때부터 잘 알아봤어야 하는건데 이미 기능구현을 완료하고 나서 발견했던 것이라 많이 아쉬웠다ㅠㅠ 앞으로 충분히 조사를 하고 어떤 식으로 코드를 작성해야할지 정리를 한후에 진행해야겠다.