[Spring Boot] OAuth 2.0 (카카오 로그인)

이상협·2023년 2월 8일
1

Spring Boot

목록 보기
10/13

진행중인 프로젝트에서 로그인 기능을 구현해야 하는데, 소셜 로그인을 사용하기로 했다.
그래서 OAuth 2.0을 사용해서 카카오를 통해 사용자 정보를 취득하기로 했다.

동작 흐름

카카오 공식문서

1. Kakao Developers에 접속해서 애플리케이션 추가

과정은 생략하겠다.

2. REST API

추가한 애플리케이션을 들어가 '요약 정보' 로 들어가면 REST API키가 있다.

우리는 이 REST API를 사용할 예정이다.

3. 카카오 로그인 활성화 하기

카카오 인증 서버에 API를 요청하고 Redirect URI를 통해 code값을 반환받기 때문에
Redirect URI를 설정해준다.

4. 동의 항목 설정


어떤 사용자 정보를 받을 지 동의 항목에서 설정을 한다.

5. 카카오 로그인 API 요청하기

kauth.kakao.com/oauth/authorize?client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}&response_type=code

REST_API_KEY는 아까전에 얻은 REST KEY 키를 기입하고,
REDIRECT_URI는 code를 반환할 URI를 기입하면 된다.

  • 해당 주소로 접속하면 카카오 로그인 창이 뜨고, 로그인을 하면

    인가코드를 받게 된다.

나중에 이 인가코드를 통해 카카오에게서 토큰을 받을 수 있다.

OauthController.java

@ResponseBody
@GetMapping("/api/oauth/kakao")
public void kakaoCalllback(@RequestParam String code) {
	log.info("code : " + code);

6. token 요청하기

build.gradle

dependencies {
	implementation 'com.google.code.gson:gson:2.8.7'
}

OauthService.java

public String getKakaoAccessToken(String code) {

	String accessToken = "";
    String reqURL = "https://kauth.kakao.com/oauth/token";

        try {
            URL url = new URL(reqURL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            // POST 요청을 위해 기본값이 false인 setDoOutput을 true로 설정
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);

            // POST 요처에 필요로 요구하는 파라미터를 스트림을 통해 전송
            BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(conn.getOutputStream())));
            StringBuilder sb = new StringBuilder();
            sb.append("grant_type=authorization_code");
            sb.append("&client_id={code}");
            sb.append("&redirect_uri=http://localhost:8080/api/oauth/kakao");
            sb.append("&code=" + code);
            bw.write(sb.toString());
            bw.flush();

            // 결과 코드가 200이라면 성공
            int responseCode = conn.getResponseCode();
            log.info("responseCode : " + responseCode);

            // 요청을 통해 얻은 JSON타입의 Response 메세지 읽어오기
            String result = getRequestResult(conn);

            // Gson 라이브러리에 포함된 클래스로 JSON파싱 객체 생성
            JsonParser parser = new JsonParser();
            JsonElement element = parser.parse(result);

            accessToken = element.getAsJsonObject().get("access_token").getAsString();

            log.info("access_token : " + accessToken);

            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return accessToken;
    }

사용자 정보를 조회하면 되기 때문에 access token만 가져온다.

7. 사용자 정보 조회하기

code를 통해 얻은 access token으로 사용자 정보를 조회한다.

OauthService.java

public KakaoUserInfo getKakaoUserInfo(String token) {

        String reqURL = "https://kapi.kakao.com/v2/user/me";
        KakaoUserInfo kakaoUserInfo = new KakaoUserInfo();

        //access_token을 이용하여 사용자 정보 조회
        try {
            URL url = new URL(reqURL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setRequestMethod("GET");
            conn.setDoOutput(true);
            conn.setRequestProperty("Authorization", "Bearer " + token); //전송할 header 작성, access_token전송

            //결과 코드가 200이라면 성공
            int responseCode = conn.getResponseCode();
            log.info("responseCode : " + responseCode);

            //요청을 통해 얻은 JSON타입의 Response 메세지 읽어오기
            String result = getRequestResult(conn);

            //Gson 라이브러리로 JSON파싱
            JsonParser parser = new JsonParser();
            JsonElement element = parser.parse(result);
            JsonElement kakaoAccount = element.getAsJsonObject().get("kakao_account");
            JsonElement profile = kakaoAccount.getAsJsonObject().get("profile");

            //dto에 저장하기
            kakaoUserInfo.setId(element.getAsJsonObject().get("id").getAsLong());
//            kakaoUserInfo.setNickname(profile.getAsJsonObject().get("nickname").getAsString());
            kakaoUserInfo.setProfileImgUrl(profile.getAsJsonObject().get("profile_image_url").getAsString());
//            kakaoUserInfo.setThumnailImgUrl(profile.getAsJsonObject().get("thumbnail_image_url").getAsString());
            kakaoUserInfo.setHasBirthDay(kakaoAccount.getAsJsonObject().get("has_birthday").getAsBoolean());
            kakaoUserInfo.setHasGender(kakaoAccount.getAsJsonObject().get("has_gender").getAsBoolean());

            if (kakaoUserInfo.isHasBirthDay()) {
                kakaoUserInfo.setBirthday(kakaoAccount.getAsJsonObject().get("birthday").getAsString());
            }

            if (kakaoUserInfo.isHasGender()) {
                kakaoUserInfo.setGender(kakaoAccount.getAsJsonObject().get("gender").getAsString());
            }

            log.info(kakaoUserInfo.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return kakaoUserInfo;
    }

KakaoUserInfo.java (DTO)

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
public class KakaoUserInfo {

    private Long id;
//    private String nickname;
    private String profileImgUrl;
//    private String thumnailImgUrl;

    private String birthday;
    private boolean hasBirthDay;
    private String gender;
    private boolean hasGender;
}

마무리 후 다시 요청해보면 다음과 같은 결과가 출력된다.

  • 이제 사용자 정보를 얻었으니 다음 글에서는 Spring Security와 JWT 토큰을 통한 로그인 구현에 관한 내용이 작성될 것이다.

참고

0개의 댓글