네이버, 카카오 로그인 뿌수기 🔥

KJH·2022년 3월 27일
2

✅ 전체적인 OAuth 로그인 방법


💻 네이버 로그인 클라이언트(리액트) 코드

네이버 로그인 JDK 사용하는 방법

로그인 페이지 컴포넌트

import LoginNaver from './LoginNaver';

 <LoginNaver />

네이버 로그인 JDK 사용로직

import React, { useEffect } from 'react';
import { naverClientId, naverRedirectURL, naverSecret } from '../../utils/OAuth';

const { naver } = window;

const LoginNaver = () => {
  const initializeNaverLogin = () => {
    const naverLogin = new naver.LoginWithNaverId({
      clientId: naverClientId,
      callbackUrl: naverRedirectURL,
      clientSecret: naverSecret,
      isPopup: false, // popup 형식으로 띄울것인지 설정
      loginButton: { color: 'green', type: 3, height: '60' }, //버튼의 스타일, 타입, 크기를 지정
    });
    naverLogin.init();
  };

  useEffect(() => {
    initializeNaverLogin();
  }, []);

  return <div id='naverIdLogin' />;
};

export default LoginNaver;

반환값
http//리다이렉트 설정 url ? access-token = {토큰값} & state = {스테이트 값} & token-type = {토근타입} & expire = {만료기간}


네이버 로그인 REST API 사용하는 방법

a태그에 https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id={클라이언트아이디}&state={임의값 사용}&redirect_uri={등록한 리다이렉트 URL} 를 넣어 네이버로그인페이지로 이동시켜줍니다. 그리고 로그인이 완료되면 설정해놓은 리다이렉트 주소로 URL에 code값과 state값이 넘어옵니다.

📢 여기서 중요한 점 !!!

네이버 JDK로 로그인을 클라이언트에서 하게되면 리다이렉트로 넘겨주는 토큰은 일회성토큰이 아니라 바로 사용할 수 있는 접근토큰입니다.
따라서 서버에서 사용자 프로필정보를 바로 요청할 수 있습니다.

(이거 몰라서 해당 토큰으로 토큰발급 api 작동해서 엄청 고생했습니다...)

반대로 REST API로 클라이언트에서 요청한 경우에는 일회성토큰이므로 서버에서 한번 더 토큰발급을 해당 일회성 토큰으로 발급하고 프로필정보요청 API를 사용해야합니다.

네이버 로그인 JDK 서버 처리 로직 (Spring)

public void naverToken(String code, HttpServletResponse response) throws IOException {
    try {
        JSONParser jsonParser = new JSONParser();
        String header = "Bearer " + code;
        Map<String, String> requestHeaders = new HashMap<>();
        requestHeaders.put("Authorization", header);
        String responseBody = get(NAVER_USER_INFO_URI, requestHeaders);
        JSONObject parse = (JSONObject) jsonParser.parse(responseBody);

        JSONObject responseParse = (JSONObject) parse.get("response");
        String encodeUserName = (String) responseParse.get("name");
        String loginId = (String) responseParse.get("id");
        String email = (String) responseParse.get("email");
        String phoneNumber = (String) responseParse.get("mobile_e164");
        String userName = new String(encodeUserName.getBytes(StandardCharsets.UTF_8));
        User user = new UserRequest("social_" + loginId, userName, encode.encode("네이버"), email, phoneNumber).naverOAuthToEntity();
        if (userRepository.existsByLoginId(user.getLoginId()) == false) {
            userRepository.save(user);
        }
        String access_token = tokenProvider.create(new PrincipalDetails(user));
        response.addHeader("Authorization", "Bearer " + access_token);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

💻 카카오 로그인 클라이언트(리액트) 코드

카카오는 REST API로만 구현해서 해당 부분만 포스팅하겠습니다.

카카오 REST API 클라이언트 사용로직

// 변수처리를 위한 다른 JS 파일
export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${kakaoClientId}&redirect_uri=${kakaoRedirectURL}&response_type=code&prompt=login`;

// 로그인 페이지 해당 코드
<KakaoBtn href={KAKAO_AUTH_URL}>
  <img src={`${process.env.PUBLIC_URL}/images/kakao_login_large_narrow.png`} alt='kakaoLogin' />
</KakaoBtn>

반환값
http//리다이렉트 설정 url?code={일회성 토큰값}

별다른 state값을 로그인 요청시 url에 넣어주지 않았다면 state값은 선택사항이라 넘어오지 않을 것이다. 문서보고 헷갈리지 말자!


📢 여기서 중요한 점 !!!

이부분은 REST API를 사용했기 때문에 일회성토큰이 클라이언트로 넘어옵니다. 따라서 해당 토큰을 가지고 서버에서 한번 더 정식 토큰 발급을 요청하고 넘어온 access-token으로 사용자프로필 조회 API를 작동해야 오류가 나지 않습니다!!

또한, contentType이 올바른지 꼭 확인하세요!
제 경우에는 ContentType -> application/json로 멋대로 json으로 요청을 보냈다가
org.springframework.web.client.HttpClientErrorException$Unauthorized: 401 Unauthorized: [no body]

위와 같은 에러가 났으니 꼭 !!!
ContentType은 application/x-www-form-urlencoded;charset=utf-8 공식문서대로 진행해서 요청해주세요!!

카카오 로그인 Rest API 서버 처리 로직 (Spring)

public void kakaoToken(String code, HttpServletResponse res, HttpSession session) {
    RestTemplate rt = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
    MultiValueMap<String, String> accessTokenParams = accessTokenParams("authorization_code",KAKAO_CLIENT_ID ,code,KAKAO_REDIRECT_URI);
    HttpEntity<MultiValueMap<String, String>> accessTokenRequest = new HttpEntity<>(accessTokenParams, headers);
    ResponseEntity<String> accessTokenResponse = rt.exchange(
            KAKAO_TOKEN_URI,
            HttpMethod.POST,
            accessTokenRequest,
            String.class);
    try {
        JSONParser jsonParser = new JSONParser();
        JSONObject jsonObject = (JSONObject) jsonParser.parse(accessTokenResponse.getBody());
        session.setAttribute("Authorization", jsonObject.get("access_token"));
        String header = "Bearer " + jsonObject.get("access_token");
        System.out.println("header = " + header);
        Map<String, String> requestHeaders = new HashMap<>();
        requestHeaders.put("Authorization", header);
        String responseBody = get(KAKAO_USER_INFO_URI, requestHeaders);

        JSONObject profile = (JSONObject) jsonParser.parse(responseBody);
        JSONObject properties = (JSONObject) profile.get("properties");
        JSONObject kakao_account = (JSONObject) profile.get("kakao_account");

        Long loginId = (Long) profile.get("id");
        String email = (String) kakao_account.get("email");
        String userName = (String) properties.get("nickname");
        User kakaoUser = new UserRequest("social_" + loginId, encode.encode("카카오"), userName, email).kakaoOAuthToEntity();
        if (userRepository.existsByLoginId(kakaoUser.getLoginId()) == false) {
            userRepository.save(kakaoUser);
        }
        String access_token = tokenProvider.create(new PrincipalDetails(kakaoUser));
        res.setHeader("Authorization", "Bearer "+access_token);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

몇가지 추가 당부

  1. 로그인페이지로 이동할 수 없다면 네이버, 카카오 개발자 페이지에서 내 어플리케이션 도메인 서비스 url에 개발중인 클라이언트 주소가 넣어져있는지 확인하자(ex : http//localhost:3000)
  2. 서버에서 에러가 난다면 필수 param값을 빠뜨렸는지 확인한다.
  3. 401에러가 난다면 contentType이 올바른지, 혹시 보안설정을 추가로 해서 secret값을 추가로 넣어야하는지 확인하자.

결국 모든 것은 설정만 잘하고 사용하면 문제가 생길리 없다.... ✨

🔗 참조

OAuth 로직 사진 참조

profile
Front-End Developer

0개의 댓글