Spring-React : 카카오 소셜 로그인 + JWT (2) 카카오에서 회원정보 요청후 DB에 저장하기

우진·2022년 4월 26일
4
post-thumbnail
post-custom-banner

(2) 카카오에서 회원정보 요청후 DB에 저장하기


서론.

해당 프로젝트에서는 오로지 카카오 소셜 로그인 만 사용한다. ( ID/PW 사용안함! )

이전 포스팅✅에서는 프론트에서 받은 인가코드로 카카오 서버에서 엑세스 토큰을 발급받았다.
이어서 발급받은 토큰을 이용해 해당 사용자의 프로필 정보를 받아 DB에 저장해보자.


사용한 의존성 🍃

기본 의존성 :
Spring Web
Spring boot DevTools
Lombok
Spring Security
MySQL Driver
spring Data JPA


추가한 의존성 :
jackson-databind
jackson-datatype-jsr310
java-jwt



1. 어플리케이션 동의 항목 확인하기


카카오 개발자 사이트에서 내 어플리케이션을 만들었을때, 동의 항목도 설정했을 것이다. 혹시 하지 않았다면 지금이라도 설정하자.😙





동의 항목을 이렇게 세개 받도록 설정했다. 이 부분은 각자 필요한 정보에 동의 체크를 받으면 된다!


2. UserController 수정하기


이전 포스팅에서 만들었던 api에 로직을 추가해줄 것이다.
발급받은 엑세스 토큰을 이용해 카카오 서버에서 사용자 정보를 요청하고, 그 사용자 정보를 DB에 저장하는 기능까지 넣어보겠다.


@RestController 
@RequestMapping("/api")
public class UserController {

    @Autowired
    private UserService userService; 

    // 프론트에서 인가코드 받아오는 url
   @GetMapping("/oauth/token")
   public User getLogin(@RequestParam("code") String code) {

       // 넘어온 인가 코드를 통해 access_token 발급
       OauthToken oauthToken = userService.getAccessToken(code);
       
       //(1)
       // 발급 받은 accessToken 으로 카카오 회원 정보 DB 저장
       String User = userService.saveUser(oauthToken.getAccess_token());

       return User;
   }

}
  1. UserService에 해당 메소드를 추가해준다.


3. UserService 수정하기

@Service
public class UserService {

    @Autowired
    UserRepository userRepository;
    

. . . (생략)


public User saveUser(String token) {

		//(1)
        KakaoProfile profile = findProfile(token);

		//(2)
        User user = userRepository.findByKakaoEmail(profile.getKakao_account().getEmail());
        
        //(3)
        if(user == null) {
            user = User.builder()
                    .kakaoId(profile.getId())
                     //(4)
                    .kakaoProfileImg(profile.getKakao_account().getProfile().getProfile_image_url())
                    .kakaoNickname(profile.getKakao_account().getProfile().getNickname())
                    .kakaoEmail(profile.getKakao_account().getEmail())
                     //(5)
                    .userRole("ROLE_USER").build();

            userRepository.save(user);
        }

        return user;
    }
    
    
    //(1-1)
    public KakaoProfile findProfile(String token) {
        
        //(1-2)
        RestTemplate rt = new RestTemplate();

		//(1-3)
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + token); //(1-4)
        headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");

		//(1-5)
        HttpEntity<MultiValueMap<String, String>> kakaoProfileRequest =
                new HttpEntity<>(headers);

		//(1-6)
        // Http 요청 (POST 방식) 후, response 변수에 응답을 받음
        ResponseEntity<String> kakaoProfileResponse = rt.exchange(
                "https://kapi.kakao.com/v2/user/me",
                HttpMethod.POST,
                kakaoProfileRequest,
                String.class
        );

		//(1-7)
        ObjectMapper objectMapper = new ObjectMapper();
        KakaoProfile kakaoProfile = null;
        try {
            kakaoProfile = objectMapper.readValue(kakaoProfileResponse.getBody(), KakaoProfile.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return kakaoProfile;
    }


3-1. saveUser(), findProfile() 메소드 만들기

  1. findProfile()이라는 메소드를 이용해 엑세스 토큰으로 카카오 서버에서 사용자 정보를 가져온다. 해당 메소드는 saveUser() 메소드 아래에 구현한다.
    1. 응답 받은 Json 데이터와 정확히 일치하는 KakaoProfile 클래스를 만든다.(👇아래 참고)

    2. 통신에 필요한 RestTemplate 객체를 만든다. 이후 이어질 부분은 이전 포스팅에서 설명했기 때문에 간단히 짚고 넘어가겠다.

    3. HttpHeader 객체를 생성한다.

    4. 헤더에는 발급받은 엑세스 토큰을 넣어 요청해야한다. 카카오 공식 문서를 참고하자.
    5. HttpHeaderHttpBody 정보를 하나의 객체에 담아준다.

    6. 해당 주소로 Http 요청을 보내 String 변수에 응답을 받는다.

    7. Json 응답을 KakaoProfile 객체로 변환해 리턴해준다.

  2. UserReapository 에 만들어뒀던 findByKakaoEmail() 메소드를 이용해 User 객체에 담아준다.
  3. DB에 사용자를 저장하기 전, 이미 존재하는 사용자인지 체크할 필요가 있다.
    이를 user 변수의 값이 null인지 아닌지로 판단한다. 만약 null 이라면 DB에 저장되지 않은 사용자이므로 사용자 저장 로직을 실행한다.
  4. 카카오 프로필 이미지는 Properties 가 아닌 KakaoAccount 에서 가져온다. 자세한 설명은 👇아래에 있다.
  5. 사용자의 Role(권한)은 ROLE_USER 로 고정한다.




3-2. KakaoProfile 클래스 만들기


내가 응답받은 Json 데이터의 구조는 아래와 같다.
만약 동의 항목 체크를 나와 다르게 했다면 콘솔에 한 번 찍어보고 만드는 것을 추천한다.

    {
      "id":{},
      "connected_at":"{}",

      "properties":{
          	"nickname":"{}",
          	"profile_image":"{}",
          	"thumbnail_image":"{}
       },

       "kakao_account":{
       		"profile_nickname_needs_agreement":false,
            "profile_image_needs_agreement":false,

            "profile":{
                  "nickname":"{}",
                  "thumbnail_image_url":"{}",
                  "profile_image_url":"{}",
                  "is_default_image":false
             },

             "has_email":true,
             "email_needs_agreement":false,
             "is_email_valid":true,
             "is_email_verified":true,
             "email":"{}"
        }
	}


만들어둔 model/oauth 패키지 안에 KakaoProfile 이라는 클래스를 만든다.


@Data
public class KakaoProfile {

    public Long id;
    public String connected_at;
    public Properties properties;
    public KakaoAccount kakao_account;

    @Data
    public class Properties { //(1)
        public String nickname;
        public String profile_image; // 이미지 경로 필드1
        public String thumbnail_image;
    }

    @Data
    public class KakaoAccount { //(2)
        public Boolean profile_nickname_needs_agreement;
        public Boolean profile_image_needs_agreement;
        public Profile profile;
        public Boolean has_email;
        public Boolean email_needs_agreement;
        public Boolean is_email_valid;
        public Boolean is_email_verified;
        public String email;

        @Data
        public class Profile {
            public String nickname;
            public String thumbnail_image_url;
            public String profile_image_url; // 이미지 경로 필드2
            public Boolean is_default_image;
        }
    }
    
}

  1. 카카오 프로필 이미지를 가져올 경우 Properties 클래스에서 가져오지 않는게 좋다!!
  2. Properties 클래스의 이미지는 null 이지만 KakaoAccount 클래스의 이미지는 null 이 아닌 경우가 있었다. DB 컬럼을 모두 not null 로 설정했다면 여기서 이미지 가져오는 거 추천한다. 이거 때문에 토큰까지 다 구현해놓고 오류가 나서 허겁지겁 바꿨던 기억이 있다...😢



도움 받은 영상 :
https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9


마치며.

여기까지 잘 따라왔다면 UserController 에 만든 api를 동작 시켜보자. 정상적으로 정보를 넣은 상태라면 KakaoProfile 객체에 값이 잘 담겨 있고, DB에도 사용자 정보가 잘 저장되어 있을 것이다.
다음은 JWT 토큰의 개념과 토큰 발급을 위한 준비과정에 대해 적어볼 예정이다. 많관부많관부~🥳💖

profile
백 개발을 시작한 응애개발자
post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 4월 26일

기대됩니다

답글 달기
comment-user-thumbnail
2024년 7월 25일

User 클래스와 KakaoProfile 클래스의 차이가 뭔가요?

답글 달기