본문 바로가기
▶ Back-End/Java

SNS 간편로그인 - 카카오 로그인 API 호출 및 사용자 정보 받기

by 오늘도 코딩 2024. 7. 11.
728x90
반응형

Spring Boot에서 RestTemplate을 통해 카카오 Open API를 호출하여 사용자 정보 받기

*SNS 간편로그인 - 카카오 API 사용 등록 방법 완료 후 진행(관련 글 참고)

*프로세스는 아래 카카오 공식 문서 참고(구글과 네이버 모두 동일)

*Swagger3 관련 소스 포함

*자세한 설명 생략

 

 

▷ application.properties 설정

#KAKAO
kakao.client.id="KAKAO에서 제공한 Client ID"
kakao.redirect.uri="KAKAO에 설정한 Redirect URI"

 

 

▷ kakao.html

*로그인 화면(간단히 버튼만 생성)

<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>카카오 테스트 페이지</title>
</head>
<body>
   <div align="center">
      <h1>카카오 로그인 테스트</h1><br><br>
      
      <a th:href="
         @{https://kauth.kakao.com/oauth/authorize(
              client_id=${clientId},
              redirect_uri=${redirectUri},
              response_type=${responseType}
              )}">
         <img src="/images/kakao_login_btn.png">
      </a>
   </div>
</body>
</html>

 

 

▷ CmmUtil.java

*공통 유틸리티

/**
 * 공통 유틸리티
 */
public class CmmUtil {

   /**
     * 
     * Object to String
     * 
     * @param Object
     * @return String
     * @throws JsonProcessingException
     */
    public static String getObjStr(Object obj) throws JsonProcessingException {
        return new ObjectMapper()
                .registerModule(new JavaTimeModule())
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .writeValueAsString(obj);
    }
}

 

 

▷ KakaoController.java

* 로그인 화면 진입 Controller 생성

/**
 * 카카오 TEST Controller
 */
@Controller
@RequestMapping("test")
public class KakaoContrller {
   
   @Value("${kakao.client.id}")
   private String KAKAO_CLIENT_ID;

   @Value("${kakao.redirect.uri}")
   private String KAKAO_REDIRECT_URI;

   @GetMapping("/kakao.do")
    public String kakaoLogin(Model model){
      
        model.addAttribute("clientId", KAKAO_CLIENT_ID);
        model.addAttribute("redirectUri", KAKAO_REDIRECT_URI);
        model.addAttribute("responseType", "code");
        
        return "kakao";
    }
   
}

 

 

 ▷ LGN1001Controller.java

*Redirect Controller 생성

/**
 * 카카오 Login Controller
 */
@Slf4j
@RestController
@RequestMapping("xxxx")
@Tag(name = "LGN", description = "Login Controller")
public class LGN1001Controller {

   @Autowired
   private LGNService lgnService;

   @GetMapping("/kakao/login.do")
   @Operation(summary = "XXXX-LGN-1001", description = "[카카오] 로그인(Redirect)")
   public LGN1001ResVO lgn1001(@Parameter(description = "인가 코드") @RequestParam("code") String code) {

      LGN1001ResVO resVO = new LGN1001ResVO();

      try {

         resVO = lgnService.getLGN1001(code);

         log.info("[카카오] 로그인 최종 응답");
         log.info(CmmUtil.getObjStr(resVO));
      } catch (Exception e) {
	  
      }

      return resVO;
   }

}

 

 

▷ LGN1001ResVO.java

*최종 응답 VO

/**
 * [카카오] 로그인 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "[카카오] 로그인 응답 VO")
public class LGN1001ResVO extends CmmResVO {

   /** 결과 값 */
   @JsonProperty("result")
   @Schema(description = "결과 값")
   public LGN1001VO result;

   @Getter
   @Setter
   @ToString
   @Schema(description = "[카카오] 로그인 응답 VO")
   public static class LGN1001VO {

      @JsonProperty("id")
      @Schema(description = "ID")
      public long id;

      @JsonProperty("connected_at")
      @Schema(description = "서비스에 연결 완료된 시각")
      public String connectedAt;

      @JsonProperty("kakao_account")
      @Schema(description = "카카오계정 정보")
      public KakaoAccountVO kakaoAccount;

      @JsonProperty("properties")
      @Schema(description = "사용자 프로퍼티")
      public propertiesVO properties;

      @Getter
      @Setter
      @ToString
      @Schema(description = "카카오계정 정보 VO")
      public static class KakaoAccountVO {

         @JsonProperty("profile_nickname_needs_agreement")
         @Schema(description = "사용자 동의 시 닉네임 제공 가능")
         public boolean profileNicknameNeedsAgreement;

         @JsonProperty("profile")
         @Schema(description = "프로필 정보")
         public ProfileVO profile;

      }

      @Getter
      @Setter
      @ToString
      @Schema(description = "프로필 정보 VO")
      public static class ProfileVO {

         @JsonProperty("nickname")
         @Schema(description = "닉네임")
         public String nickname;

         @JsonProperty("is_default_nickname")
         @Schema(description = "닉네임이 기본 닉네임인지 여부")
         public Boolean isDefaultNickname;
      }

      @Getter
      @Setter
      @ToString
      @Schema(description = "사용자 프로퍼티 VO")
      public static class propertiesVO {

         @JsonProperty("nickname")
         @Schema(description = "닉네임")
         public String nickname;
      }

   }

}

 


▷ CmmResVO.java

*공통 응답

/**
 * 공통 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "공통 응답 VO")
public class CmmResVO {

    /** Result Code */
    @JsonProperty("resultCode")
    @Schema(description = "Result Code")
    public String resultCode = "0000";

    /** Result Msg */
    @JsonProperty("resultMsg")
    @Schema(description = "Result Msg")
    public String resultMsg = "성공";

    /** Set Result */
    public CmmResVO setResCmmResult(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;

        return this;
    }
}

 

 

▷ LGNService.java

/**
 * Login Service
 */
public interface LGNService {

   /** [카카오] 로그인 **/
   public LGN1001ResVO getLGN1001(String code);
}

 

 

▷ LGNServiceImpl.java

/**
 * Login ServiceImpl
 *
 */
@Service
public class LGNServiceImpl implements LGNService {

   @Autowired
   private KakaoApiService kakaoApi;

   /**
    * [카카오] 로그인
    */
   @Override
   public LGN1001ResVO getLGN1001(String code) {

      LGN1001ResVO result = new LGN1001ResVO();

      try {

         /* [카카오] 토큰 발급 */
         KakaoOAuthTokenVO token = kakaoApi.getOAuthToken(code);

         /* [카카오] 사용자 정보 조회 */
         KakaoUserInfoVO userInfo = kakaoApi.getUserInfo(token.getAccess_token());

         /* 사용자 정보 저장 */

         /* 응답 값 설정 */
         ProfileVO profileVO = new ProfileVO();
         profileVO.setNickname(userInfo.getKakaoAccount().getProfile().getNickname());
         profileVO.setIsDefaultNickname(userInfo.getKakaoAccount().getProfile().getIsDefaultNickname());

         KakaoAccountVO kakaoAccountVO = new KakaoAccountVO();
         kakaoAccountVO.setProfileNicknameNeedsAgreement(userInfo.getKakaoAccount().isProfileNicknameNeedsAgreement());
         kakaoAccountVO.setProfile(profileVO);

         propertiesVO propertiesVO = new propertiesVO();
         propertiesVO.setNickname(userInfo.getProperties().getNickname());

         LGN1001VO vo = new LGN1001VO();
         vo.setId(userInfo.getId());
         vo.setConnectedAt(userInfo.getConnectedAt());
         vo.setKakaoAccount(kakaoAccountVO);
         vo.setProperties(propertiesVO);

         result.setResult(vo);

      } catch (Exception e) {
         
      }

      return result;
   }

}

 

 

▷ KakaoOAuthTokenVO.java

/**
 * [카카오] 토큰 발급 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "[카카오] 토큰 발급 응답 VO")
@JsonIgnoreProperties(ignoreUnknown = true)
public class KakaoOAuthTokenVO {

   @JsonProperty("access_token")
   @Schema(description = "갱신된 사용자 액세스 토큰 값")
   public String access_token;
   
   @JsonProperty("refresh_token")
   @Schema(description = "갱신된 사용자 리프레시 토큰 값, 기존 리프레시 토큰의 유효기간이 1개월 미만인 경우에만 갱신")
   public String refresh_token;
   
}

 

 

KakaoUserInfoVO.java

/**
 * [카카오] 사용자 정보 조회 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "[카카오] 사용자 정보 조회 응답 VO")
@JsonIgnoreProperties(ignoreUnknown = true)
public class KakaoUserInfoVO {

   @JsonProperty("id")
   @Schema(description = "ID")
   public long id;

   @JsonProperty("connected_at")
   @Schema(description = "서비스에 연결 완료된 시각")
   public String connectedAt;

   @JsonProperty("kakao_account")
   @Schema(description = "카카오계정 정보")
   public KakaoAccountVO kakaoAccount;

   @JsonProperty("properties")
   @Schema(description = "사용자 프로퍼티")
   public propertiesVO properties;

   @Getter
   @Setter
   @ToString
   @Schema(description = "카카오계정 정보 VO")
   @JsonIgnoreProperties(ignoreUnknown = true)
   public static class KakaoAccountVO {

      @JsonProperty("profile_nickname_needs_agreement")
      @Schema(description = "사용자 동의 시 닉네임 제공 가능")
      public boolean profileNicknameNeedsAgreement;

      @JsonProperty("profile")
      @Schema(description = "프로필 정보")
      public ProfileVO profile;

   }

   @Getter
   @Setter
   @ToString
   @Schema(description = "프로필 정보 VO")
   @JsonIgnoreProperties(ignoreUnknown = true)
   public static class ProfileVO {

      @JsonProperty("nickname")
      @Schema(description = "닉네임")
      public String nickname;

      @JsonProperty("is_default_nickname")
      @Schema(description = "닉네임이 기본 닉네임인지 여부")
      public Boolean isDefaultNickname;
   }

   @Getter
   @Setter
   @ToString
   @Schema(description = "사용자 프로퍼티 VO")
   @JsonIgnoreProperties(ignoreUnknown = true)
   public static class propertiesVO {

      @JsonProperty("nickname")
      @Schema(description = "닉네임")
      public String nickname;
   }

}

 

 

▷ KakaoApiService.java

/**
 * 카카오 API Service
 * 
 * https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
 */
public interface KakaoApiService {
   
   /** [카카오] 토큰 발급 **/
   public KakaoOAuthTokenVO getOAuthToken(String code);
   
   /** [카카오] 사용자 정보 조회 **/
   public KakaoUserInfoVO getUserInfo(String accessToken);
   
}

 

 

▷ KakaoApiServiceImpl.java

/**
 * 카카오 API ServiceImpl
 *
 */
@Slf4j
@Service
public class KakaoApiServiceImpl implements KakaoApiService {

   @Value("${kakao.client.id}")
   private String KAKAO_CLIENT_ID;

   @Value("${kakao.redirect.uri}")
   private String KAKAO_REDIRECT_URI;

   /**
    * [카카오] 토큰 발급
    */
   @Override
   public KakaoOAuthTokenVO getOAuthToken(String code) {

      KakaoOAuthTokenVO result = new KakaoOAuthTokenVO();

      try {
         log.info("[카카오] 토큰 발급 시작");

         if (code == null) {
            return result;
         }

         /* 요청 */
         final String uri = "https://kauth.kakao.com/oauth/token";

         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // MultiValueMap

         MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
         body.add("grant_type", "authorization_code");
         body.add("client_id", KAKAO_CLIENT_ID);
         body.add("redirect_uri", KAKAO_REDIRECT_URI);
         body.add("code", code);

         /* 응답 */
         ResponseEntity<String> res = new RestTemplate().postForEntity(uri, new HttpEntity<>(body, headers), String.class);
         result = new ObjectMapper().readValue(res.getBody(), KakaoOAuthTokenVO.class);

         log.info("[카카오] 토큰 발급 종료");
      } catch (Exception e) {
	  
      }

      return result;
   }

   /**
    * [카카오] 사용자 정보 조회
    */
   @Override
   public KakaoUserInfoVO getUserInfo(String accessToken) {

      KakaoUserInfoVO result = new KakaoUserInfoVO();

      try {
         log.info("[카카오] 사용자 정보 조회 시작");

         if (accessToken == null) {
            return result;
         }

         /* 요청 */
         final String uri = "https://kapi.kakao.com/v2/user/me";

         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // MultiValueMap
         headers.add("Authorization", "Bearer " + accessToken);

         /* 응답 */
         ResponseEntity<String> res = new RestTemplate().postForEntity(uri, new HttpEntity<>(headers), String.class);
         result = new ObjectMapper().readValue(res.getBody(), KakaoUserInfoVO.class);

         log.info("[카카오] 사용자 정보 조회 종료");
      } catch (Exception e) {
      
      }

      return result;
   }

}

 

 

▷ 결과

소스가 수정됨에 결과화면과 다를 수 있음

 

 

▷ 관련 글

 

SNS 간편로그인 - 카카오 API 사용 등록 방법

카카오 Open API를 사용하기 위한 카카오 developers 앱 등록*자세한 설명 생략  ▷ 카카오 API 사용 등록 방법  ① 내 애플리케이션 생성 Kakao Developers카카오 API를 활용하여 다양한 어플리케이션을

coding-today.tistory.com

 

RestTemplate Post 요청 보내기

RestTemplate로 Post 요청을 보내고, 응답 코드를 확인하는 메서드*Header 값(Authorization)만 추가하고, Body는 빈 값으로 요청*자세한 설명 생략   /** * POST 요청 */public static boolean sendPost(String jwt) { boolean r

coding-today.tistory.com

 

Objcet to String

Object를 String으로 변환하는 간단한 방법 /** * * Object to String * * @param Object * @return String */ public static String getObjStr(Object obj) { String str = ""; try { str = new ObjectMapper().writeValueAsString(obj); } catch (Exception e)

coding-today.tistory.com

 

JSON Unrecognized field 해결방법(@JsonIgnoreProperties)

JSON 데이터를 구성하는 요소가 가변적일 때 무시하는 방법 *소스는 변하지 않았지만 연동 했던 API 응답 값이 변했다고 가정 ▷ ERROR - JSON 데이터를 매핑하지 못해 에러 발생 com.fasterxml.jackson.databi

coding-today.tistory.com

 

SNS 간편로그인 - 구글 API 사용 등록 방법

구글 Open API를 사용하기 위한 구글 developers 사용 설정*자세한 설명 생략  ▷ 구글  API 사용 등록 방법 ⓛ 프로젝트 생성 Google 클라우드 플랫폼로그인 Google 클라우드 플랫폼으로 이동accounts.goog

coding-today.tistory.com

 

SNS 간편로그인 - 네이버 API 사용 등록 방법

네이버 Open API를 사용하기 위한 네이버 developers 앱 등록*자세한 설명 생략  ▷ 네이버 API 사용 등록 방법 ① 내 애플리케이션 생성 애플리케이션 - NAVER Developers developers.naver.com  ▷ 관련 글 S

coding-today.tistory.com

 

 

▷ 참고

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

[Spring] 카카오 로그인 API 사용 방법

Kakao Developers이미지 설명에 각 이미지 내용에 대한 위치(경로) 적어뒀으니 참고해 주세요. 1. KakaoDevelopers 접속https://developers.kakao.com/ Kakao Developers카카오 API를 활용하여 다양한 어플리케이션을

innovation123.tistory.com

 

 

728x90
728x90

댓글