Oauth2로 소셜로그인 - 직접 구현

CodeKong의 기술 블로그·2024년 1월 9일
2

SPRING BOOT

목록 보기
23/24
post-thumbnail

오늘은 저번 소셜로그인 원리에 이어 직접 raw하게 코드를 구현해보겠습니다.

기초설정은 https://velog.io/@joonoo3/Oauth2로-소셜로그인-기초-원리-카카오 이곳에서 참고해주세요!


🔖 진행도

이전 포스트에서 올렸던 자료인데 기초 설정만으로 얼마나 해주는지 살펴보겠습니다.

스프링부트를 실행해주고
http://localhost:8080/oauth2/authorization/kakao 에 접속해봅니다.

이와 같이 https://kauth.kakao.com/oauth/authorize?~ 주소로 리다이렉트 되는것을 확인할 수 있습니다.


개발자 도구에서도 확인할 수 있습니다!

이제 동의를 누르면 카카오 서버에서는 미리 설정해둔 리다이렉트 url인
http://localhost:8080/oauth2/kakao~ 로 인가코드를 보내줄겁니다!

그럼 저희도 /oauth2/kakao를 받아 매핑할 controller를 만들어줘야겠죠?


📌 인가 코드 받기


카카오 디벨로퍼스 https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-code-sample 에 있는 내용입니다. code값으로 param을 받아와야 하겠네요!

간단한 controller하나를 만들어 줍니다.

@GetMapping("/oauth2/kakao")
    public String kakaoCode(@RequestParam("code") String code) {
        return code;
    }

다시 로그인 해주면

code는 잘꺼내오는 것을 확인할 수 있습니다!


📌 토큰 받아오기

이제 카카오에 정상적으로 로그인 했다는 인가코드를 받았으니 사용자 정보를 알아오기 위한 토큰을 받아오겠습니다!

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token-request 에 있는 내용을 보면

여러 값을 param으로 건네주어야 함을 알 수 있습니다.

그래서 컨트롤러에 변수를 선언하고 Value로 값을 주입해주고 WebFlux설정을 해줍니다.

Value 어노테이션 사용법 : https://velog.io/@joonoo3/Spring-BootAnnotation-Value

@RestController
@RequestMapping
@RequiredArgsConstructor
@Slf4j
public class AuthController {

    @Value("${spring.security.oauth2.client.registration.kakao.client-id}")
    private String clientId;
    @Value("${spring.security.oauth2.client.registration.kakao.client-secret}")
    private String clientSecret;
    @Value("${spring.security.oauth2.client.registration.kakao.redirect-uri}")
    private String redirectUri;

    @GetMapping("/oauth2/kakao")
    public Oauth2TokenDTO kakaoLogin(@RequestParam("code") String code) {

        String targetUrl = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id="
                + clientId + "&redirect_uri=" + redirectUri + "&code=" + code + "&client_secret=" + clientSecret;
        WebClient webClient = WebClient.builder()
                .baseUrl(targetUrl)
                .build();

        log.info("targetUrl : {}", targetUrl);

        Oauth2TokenDTO json = webClient
                .post()
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .retrieve()
                .bodyToMono(Oauth2TokenDTO.class)
                .block();

        return json;
    }

}

참고로 Oauth2TokenDTO는 https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token-response 에 있는 반환값을 토대로 작성한 클래스 입니다.
밑 코드를 참고하세요!

@Builder
@Getter
@RequiredArgsConstructor
@AllArgsConstructor
public class Oauth2TokenDTO {

    private String access_token;
    private String refresh_token;
    private String token_type;
    private Long expires_in;
    private String scope;
    private String refresh_token_expires_in;

}

이제 다시로그인 해주면

토큰이 잘 넘어옴을 확인 할 수 있습니다!


💡 추가 - 사용자 정보 받아오기

사실 여기까지 하면 사용자 정보는 위와 같이 WebClient로 카카오에서 제공하는 API로 요청을
보내면 받을 수 있습니다.

이 후 포스팅에서 Oauth2 라이브러리를 사용하여 훨씬 더 쉽게 유저 정보를 받아올 수 있어서 이 부분은 raw 코드로 더 완성시키고 싶은 분에게 추천합니다.

먼저, 카카오 디벨로퍼 https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info에서 제공하는 유저정보 API 엔드포인트는 https://kapi.kakao.com/v2/user/me 입니다.

헤더는 엑세스 토큰을 요구하고 있으니 WebClient을 두번 써야 하겠네요.
코드가 길어질 것 같으니 메서드를 추출하겠습니다.

@GetMapping("/oauth2/kakao")
    public KakaoUserInfoDTO kakaoLogin(@RequestParam("code") String code) {

        Oauth2TokenDTO json = getOauth2TokenDTO(code);

        KakaoUserInfoDTO authorization = getKakaoUserInfoDTO(json);

        return authorization;
    }

	//유저 정보 받아오기
    private KakaoUserInfoDTO getKakaoUserInfoDTO(Oauth2TokenDTO json) {
        String UserInfoUrl = "https://kapi.kakao.com/v2/user/me";

        WebClient webClient2 = WebClient.builder()
                .baseUrl(UserInfoUrl)
                .build();

        KakaoUserInfoDTO userInfo = webClient2.post()
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .headers(httpHeaders ->
                        httpHeaders.add("Authorization", "Bearer " + json.getAccess_token())
                ).retrieve().bodyToMono(KakaoUserInfoDTO.class)
                .block();

        return userInfo;
    }

	//토큰 얻어오기
    private Oauth2TokenDTO getOauth2TokenDTO(String code) {

        String targetUrl = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id="
                + clientId + "&redirect_uri=" + redirectUri + "&code=" + code + "&client_secret=" + clientSecret;
        WebClient webClient = WebClient.builder()
                .baseUrl(targetUrl)
                .build();

        log.info("targetUrl : {}", targetUrl);

        Oauth2TokenDTO token = webClient
                .post()
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .retrieve()
                .bodyToMono(Oauth2TokenDTO.class)
                .block();

        return token;
    }

참고로 KakaoUserInfoDTO 는 파싱하기 쉽게 만든 객체입니다!

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class KakaoUserInfoDTO {

    private Long id;
    private Boolean has_signed_up;
    private String connected_at;
    private String synched_at;
    private String properties;
    private KakaoAccount kakao_account;
    private String for_partner;


    @Builder
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class KakaoAccount{
        private Boolean profile_nickname_needs_agreement;
        private Boolean profile_image_needs_agreement;
        private Boolean has_email;
        private Boolean email_needs_agreement;
        private Boolean is_email_valid;
        private Boolean is_email_verified;
        private String email;
    }

}

다시 로그인 해보면

잘 반환 되었네요!

다음 포스팅에서는 기존 코드를 모두 자동화해주는 Oauth 라이브러리를 사용해보겠습니다!

0개의 댓글