개발환경, 도구/오픈API

kakao developers - 로그인

gu9gu 2022. 12. 29. 23:48

1. kakao developers - 로그인 - 내 어플리케이션

 - 어플리케이션 추가

 

2. 어플리케이션 접속

 - 환경에 맞게 key 사용 ( Rest API Key 사용할 것.. 클라이언트 키 역할)

 

3. 접속한 어플리케이션 - 플랫폼 설정하기

 - web 플랫폼 등록

       └ 도메인을 따로 구매하지 않았고 테스트 용도인 경우 : http://localhost:8000

 

4. 접속한 어플리케이션 - 카카오 로그인(왼쪽메뉴)

 - 활성화 설정 : 상태 ON

 - Redirect URI ( 로그인이 정상적으로 되고 카카오로부터 응답 받을 주소) : http://localhost:8000/auth/kakao/callback        

 - Logout Redirect URI : http://localhost:8000/auth/kakao/logout

 

5. 접속한 어플리케이션 - 동의항목 - 개인정보

 - 프로필 정보(닉네임/프로필 사진) / profile

      동의 단계 : 필수 동의

      └ 동의목적 : 카카오 로그인 개발 테스트

 - 카카오계정(이메일) / account_email

       동의 단계 : 필수 동의(개발 과정이라 선택 불가), '선택 동의'로 일단 한다.

      └ 동의목적 : 카카오 로그인 개발 테스트

 

6. 접속한 어플리케이션 - 간편가입

  건드릴 거 없음

 

7. 문서 - 카카오 로그인 - 디자인 가이드

  - 카카오 로그인 버튼 리소스 다운해서 resource/image/ 에 넣기 : 축약형 Middel의 png 파일 다운해서 사용

 

8. 문서 - REST API - 인가 코드 받기

                            참고 - REST API | Kakao Developers 문서1

 - 요청 주소 만들고 다운 받은 버튼 이용해서 추가하기

 

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

   -  ${REST_API_KEY} 는 kakao developers에 등록한 어플리케이션에서 발급받은 어플리케이션 Rest API Key 

   -  ${REDIRECT_URI}kakao developers에 등록한 어플리케이션에서 설정한 Redirect URI

   -  response_type 는 code 고정

   - 위 3개는 필수 파라미터고 추가적으로 scope, prompt 등이 있다.

 

html 코드

<!-- 카카오 로그인 버튼
 - resource/image/ 에 버튼 이미지 추가 필요
-->
<a href="https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code"><img height="38px" src="/image/kakao_login_medium_button.png"/></a>

 

9. redirect 받는 controller 추가

@GetMapping("/auth/kakao/callback")
public @ResponseBody String kakaoCallback(@RequestParam String code) {  // @ResponseBody를 붙이면 Data를 리턴해주는 컨트롤러함수가 된다.
    System.out.println("code = " + code);
    return "카카오 인증 완료";
}

 

10. 토큰 받기

post방식 https://kauth.kakao.com/oauth/token

application/x-www-form-urlencoded;charset=utf-8

 은 key-value로 전달하라는 뜻

/*
 * 카카오 서버로 요청 (POST 방식으로 key=value 데이터 형식)
 * ( java POST요청은 보통 Retorfit2, OkHttp, RestTemplate 방식들 중 한개를 사용함)
 * */
// HttpHeader 오브젝트 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8\n");

// HttpBody  오브젝트 생성
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code"); // authorization_code로 고정
params.add("client_id",REST_API_KEY); // 앱 REST API 키
params.add("redirect_uri", REDIRECT_URI); // 인가 코드가 리다이렉트된 URI
params.add("code", code); // 인가 코드 받기 요청으로 얻은 인가 코드

// HttpHeader와 HttpBody를 하나의 오브젝트에 담기 ( 이유 : exchange에서 HttpEntity<?>를 받기 때문)
HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest =
        new HttpEntity<>(params, headers);

// Http 요청 후 response에 응답받음
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response = rt.exchange(
        "https://kauth.kakao.com/oauth/token",
        HttpMethod.POST,
        kakaoTokenRequest,
        String.class
);

반환 받은 response에서 expires_in동안 access_token을 이용하면 scope에 지정된 범위 하에 카카오자원서버에 접근할 수 있다.

 

11. 사용자 정보 가져오기

	// HttpHeader 오브젝트 생성
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
        headers.add("Authorization", "Bearer " +KakaoTokenResponse.getAccess_token());

        // HttpBody  오브젝트 생성
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        //  property_keys 포함시 400error(파싱 문제인듯?) 반환됨.
        //params.add("property_keys", new String[]{"kakao_account.profile", "kakao_account.name","kakao_account.email"});

        // HttpHeader와 HttpBody를 하나의 오브젝트에 담기 ( 이유 : exchange에서 HttpEntity<?>를 받기 때문)
        HttpEntity<MultiValueMap<String, Object>> kakaoUserInfoRequest =
                new HttpEntity<>(params, headers);

        // Http 요청 후 response에 응답 받음
        RestTemplate rt = new RestTemplate();
        ResponseEntity<String> response = rt.exchange(
                "https://kapi.kakao.com/v2/user/me",
                HttpMethod.POST,
                kakaoUserInfoRequest,
                String.class
        );

 

12. 카카오 정보로 로그인시 흐름

 1) 카카오 로그인 버튼 클릭

 2) 엑세스 토큰 요청

 3) 카카오 사용자 정보 요청(엑세스 토큰을 이용)

 4) 카카오 사용자 정보로 가입된 정보가 DB에 존재하는지 확인 ( username으로 확인)

 5) DB에 존재하지 않으면 가입

 6) 카카오 사용자 정보로 로그인 처리

 - 스프링 시큐리티 로그인 처리를 위해 password를 고정 패스워드로 처리 ( 의문점! 실제 운영에서는 이렇게 하면 안될 거 같은데.. oAuth 라이브러리를 사용하면 다른가?)

 - 카카오 사용자 정보에서 추가적으로 받아야 하는 정보가 있는 경우 정보 기입 화면을 띄우는 방법이 있다.

    @GetMapping("/auth/kakao/callback")
    public  String kakaoCallback(@RequestParam String code
            , @Value("${kakao.springboot_blog_project.REST_API_KEY}") String REST_API_KEY
            , @Value("${kakao.springboot_blog_project.REDIRECT_URI}") String REDIRECT_URI
            ,@Value("${kakao.springboot_blog_project.PUBLIC_PASSWORD}") String PUBLIC_PASSWORD
    ) {
        // TODO: 아래 과정을 service단으로 옮길 필요는 없는 건지? (@Transactional 처리)

        // 카카오 토큰 요청
        KakaoToken KakaoToken = getKakaoTokenRequest(code, REST_API_KEY, REDIRECT_URI);
        // 카카오 사용자 정보 요청
        KakaoUserInfoResponse kakaoUserInfo = getKakaoUserInfoRequest(KakaoToken);

        User user = User.builder()
                .username(kakaoUserInfo.getKakao_account().getEmail() + "_" + kakaoUserInfo.getId())
                .password(PUBLIC_PASSWORD)
                .email(kakaoUserInfo.getKakao_account().getEmail())
                .oauth("kakao")
                .build();

        // 가입자 인지 확인
        User findUser = userService.getUser(user.getUsername());
        // 기존 회원이 아니면 회원 가입
        if( null == findUser) {
            userService.joinUser(user);
        }

        // 로그인 처리
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), PUBLIC_PASSWORD));
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 홈으로 리다이렉트
        return "redirect:/";
    }

 

 

참고

 

(1) OAuth2.0 강좌 (개념 이해하기) - YouTube

(1) oauth 2.0 (구글 API) - 2 : 동작 메커니즘 - YouTube

 

 

 

다른 방식으로  oAauth 구현 참고 - 스프링 시큐리티와 OAuth 2.0으로 로그인 기능 구현 (velog.io)