본문으로 바로가기

우선 왜 javascript SDK를 사용했냐면, 모바일 환경에서도 login in with kakaotalk소셜 로그인을 사용하고 싶었기 때문이다. REST API를 사용하게 되면 웹에서 카카오 홈페이지에 로그인하는 창이 뜨게 되어서 모바일 유저들의 경험을 해치게 된다.

 

Android SDK Android 스마트폰 가능 카카오톡에 연결된 카카오계정 정보 이용
카카오톡 미설치 시, 카카오계정 정보 입력 웹 페이지 이용
iOS SDK iOS 스마트폰 가능 카카오톡에 연결된 카카오계정 정보 이용
카카오톡 미설치 시, 카카오계정 정보 입력 웹 페이지 이용
JavaScript SDK PC 또는 모바일 웹 브라우저(Web Browser) 모바일에서만 가능 스마트폰 기기: 카카오톡에 연결된 카카오계정 정보 이용
PC 또는 Mac 기기: 카카오계정 정보 입력 웹 페이지 이용
REST API PC 또는 모바일 웹 브라우저(Web Browser) 불가능 카카오계정 정보 입력 웹 페이지 이용

 

 

방법 1. 개별 라이브러리 사용

 

react-kakao-login

react-google-login

react-facebook-login

 

전부 생긴 것도 비슷하고, 사용법도 비슷합니다.

그런데 방법 1을 사용해보니 결국 방법 3과 조화시켜야 하더군요.

 

 

방법 2. hello.js

 

(https://adodson.com/hello.js/)

 

velopert님의 프로젝트를 살펴보면서 알게된 라이브러리입니다.

hello.js를 사용하여 일괄적으로 소셜 로그인을 관리할 수 있게 됩니다.

다만 kakaotalk 기능이 없습니다. 아마 다른 프로젝트에서 사용해보지 않을까 싶습니다.

 

 

방법 3. 직접 SDK를 이용하기

 

각 회사에서 제공하는 SDK를 직접 이용하는 방법입니다.

로그인 기능 외에 다양한 기능을 곁들여서 사용하고 싶다면 SDK를 사용해야 합니다.

 


 

1. react-kakao-login 사용

 

디벨로퍼 사이트에서 도메인 등록 및 필요한 정보 설정 등은 직접 홈페이지를 보고 진행하면 됩니다.

 

코드는 다음과 같다.

import KakaoLogin from "react-kakao-login";

function KakaoLoginButton() {
  return (
    <div>
      <KakaoLoginOuter
        // rest api 키가 아닌 js 키를 사용해야 합니다.
        jsKey={"카카오 디벨로퍼 사이트에서 발급받은 js키"}
        onSuccess={(res) => console.log(res)}
        onFailure={(res) => console.log(res)}
        
        // getPofile 속성을 주지 않으면 유저 정보를 받을 수 없습니다.
        getProfile={true}
      >
      </KakaoLoginOuter>
    </div>
  );
}

 

문서에 따르면 줄 수 있는 속성은 다음과 같습니다.

jsKey	string	Required
onSuccess	function	Required
onFailure	function	Required
version	string	One of [v1, v2]. default is v2
throughTalk	bool	If true, Open Kakao Talk instead of new browser tab
getProfile	bool	If true, Can get user's information
useDefaultStyle	bool	If true, Use default style
buttonText	string	textContent of button
className	string	button's className
render	function	Can render with return of this instead of button as a child

 

유저 프로파일과 함께 출력한 결과물은 다음과 같다.

여기서 던져주는 유저 정보에 혹하지 맙시다. 유저 정보는 백단에서 관리해야 합니다.

 

물론 필요한 정보가 단순한 이메일, 식별자 뿐이라면 그냥 해당 정보를 넘겨서 백단에서 적당히 사용하기만 해도 됩니다.

 

 

 

 

🚨 주의!

JavaScript SDK의 보안 강화를 위해 리프레시 토큰을 취급하지 않도록 수정할 예정입니다. Kakao.Auth.login 및 Kakao.Auth.createLoginButton 함수를 사용한 로그인 시 발급되는 리프레시 토큰 정보(refresh_token, refresh_token_expires_in)는 2020년 7월 27일 응답에서 제외될 예정입니다.

 

사실 이 문제는 kakao 측이 독특했던 것입니다. facebook 측에서 던져주는 정보는 다음과 같습니다.

refresh token이 없죠. 

[1] {
[1]   name: 'darrern',
[1]   email: 'email@email.com',
[1]   picture: {
[1]     data: {
[1]       height: 50,
[1]       is_silhouette: false,
[1]       url: 'asdfasdf',
[1]       width: 50
[1]     }
[1]   },
[1]   id: 'asdfasdf',
[1]   accessToken: 'asdfasdf',
[1]   userID: 'asdfasdf',
[1]   expiresIn: 6371,
[1]   signedRequest: 'asdfasdf',
[1]   graphDomain: 'facebook',
[1]   data_access_expiration_time: 1602947629
[1] }

 

 

2. SDK와 토큰을 이용해 API 이용하기

 

어쨌든, 이렇게 발급된 access_token를 통해 카카오 API를 사용할 수 있습니다.(facebook, google도 마찬가지) 만료 기간이 다 되면 refrersh_token를 이용해 새로운 토큰을 받아올 수도 있지만 이 과정은 서버단에서 이뤄져야 합니다.

또, access_token은 수명이 짧기 때문에 로그인할 시에만 사용하고, 유저가 로그인을 유지해야 할 때는 서버에서 자체적으로 만든 토큰을 이용합니다.

 

refesh_token은 어차피 이후 지원이 중지될 예정이고 이는 이후 REST API를 사용해서 처리해야 하므로 여기에서는 access_token만 이용해서 유저 정보 저장 및 로그인 유지를 구현하겠습니다.

 

백단으로 토큰을 넘긴 뒤, 액세스 토큰을 이용해 유저 정보를 가져오겠습니다.

먼저 SDK 설치 먼저 진행합시다. 사용법 등은 공식 문서에 친절히 나와있습니다.

 

google api

https://www.npmjs.com/package/googleapis

주의할 점은, google 로그인을 이용하기 위해서는 google+ API를 GCP에서 활성해줘야 합니다.

넣어주지 않는다면 올바른 값을 넣어도 작동하지 않습니다.

 

 

 

google 로그인은 페이스북과 달리 정식 도메인이 없으면 시험조차 하지 못하기 때문에... 불편한 관계로 좀 자세하게 적어보겠습니다.

 

우선 프론트 단에서 로그인을 성공하면 다음과 같은 정보를 받습니다.

Aw {Da: "xx", wc: {…}, Pt: Cw, googleId: "xx", tokenObj: {…}, …}
Da: "xx"
Pt: Cw {aV: "xx", Cd: "Martin", GW: "xx", FU: undefined, fL: "xx", …}
accessToken: "xx"
googleId: "xx"
profileObj: {googleId: "xx", imageUrl: "x", email: "x", name: "x", givenName: "x", …}
tokenId: "xxxx
tokenObj: {token_type: "Bearer", access_token: "x.x-x…x", scope: "email profile x openid", login_hint: "x-x-x", expires_in: 3599, …}
wc: {token_type: "Bearer", access_token: "x.x-x…x", scope: "email profile x", expires_in: 3599, …}
__proto__: Object

 

gcp에서는 다음과 같이 설정을 해줘야하구요.

 

코드는 다음과 같이 짤 수 있겠군요

import GoogleLogin from "react-google-login";


const GoogleLoginTrigger = async (response) => {
    axios.post("/oauth/google/login", { data: response }).then((res) => {
      if (res.data.loginSuccess) {
        Cookie.set("cineps_auth", res.data.token);

        dispatch(
          isloggedin(
            res.data.bio,
            res.data.nickname,
            res.data.role,
            res.data.userImage,
            res.data.email,
            res.data._id
          )
        );

        // 로그인 성공하면 자동 홈으로 이동 처리함.
        route.push("/");
      } else {
        // 오류 발생시 처리할 곳
        alert("실패");
        route.push("/");
      }
    });
  };
  return (
    <>
      <GoogleLoginOuter
        clientId={
          "발급받은 api 키를 입력합시다"
        }
        onSuccess={GoogleLoginTrigger}
        render={(renderProps) => (
          <GoogleButton
            onClick={renderProps.onClick}
            disabled={renderProps.disabled}
          >
            <img src={"/googleLogo.png"} alt="google"></img>
            <span style={{ marginLeft: "0.5em" }}>Google로 로그인하기</span>
          </GoogleButton>
        )}
      ></GoogleLoginOuter>
    </>
  );
}

 

 

 

 

facebook sdk

https://www.npmjs.com/package/fb

 

const fb = require("fb");

//id와 name, email을 가져옵니다
FB.api('me', { fields: ['id', 'name', 'email'], access_token: 'access_token' }, function (res) {
    console.log(res);
});

 

 

kakao sdk 

https://developers.kakao.com/docs/latest/ko/sdk-download/js

 

카카오 측은 설치하지 않고, 직접 sdk 파일을 보여주고 있습니다. js파일을 하나 만들어서 내용을 그대로 복사하면 됩니다. 물론 minified된 걸로!

 

 

 

3. 정보를 가져온 이후에는?

 

소셜 로그인만 사용할 예정이므로 다음과 같은 로직으로 처리해주면 되겠습니다.

access token을 통해 유저의 정보를 가져왔다면

 

 

i. 식별자로 해당 유저의 정보가 이미 유저 DB에 있는지 확인합니다.

 

보통 소셜 로그인에는 유저를 구별하기 위한 고유한 id가 존재합니다.

=> 존재한다는 것은 이미 가입된 유저이므로 JWT만들어 줍니다.

그 후 프론트 단에 JWT 자체를 넘겨 LS에 저장하거나 res.cookies 세팅을 통해 쿠키에 저장해줍시다. 이 때 유효ㅣ간은  httpOnly: ture, maxAge는 JWT에서 지정해준 유효 기간대로 설정합시다.

 

이후 무언가 인가가 필요한 작업에서는 이 커스텀 jwt를 이용해 검증만 하면 된다.

 

이 과정에서 에러가 나면 403 반환한다.

 

 

ii. 식별자로 찾은 결과 유저 정보가 DB에 없다? 그렇다면 유저 정보에 넘어 온 emailDB를 한 번 더 찾아본다.

 

(* email이 있다면. 카카오는 email이 기본이 아니라 선택이고, facebook 쪽은 이메일이 아닌 핸드폰 번호만으로도 가입할 수 있다.) 

 

=> 그런데 있다면? 동일한 email을 가진 계정이 이미 있다는 것이므로 해당 유저의 정보를 기존 정보에 덮어씌우거나, 새로운 속성을 달아 추가해준다. , 어쨌든 로그인에 성공한 것이므로 JWT를 세팅하고 유저 정보를 프론트에 넘겨준다.

 

애초에 유저 Schema를 다음과 같이 만들어줘서 이메일을 키로 유저 정보를 식별하고, 여러 계정을 연결할 수 있도록 만들어 주는 것이 좋다.

{
  nickname
  email
  social : {
    kakao: {
      id,
      accessToken
    },
    facebook: {
      id,
      accessToken
    }
}

 

 

iii. 동일한 email 마저도 없다면?

 

신규회원이다. 

=> JWT를 세팅하고 자체 생성한 jwt와 함께 유저 정보를 프론트에 넘겨준다.

 

 

 

3. 로그인 유지하기

 

i) 새로고침을 해도 기본적으로 렌더되는 최상위 컴포넌트에서 useEffect를 써서 렌더될 때마다 유저를 체크합니다.

이래야 redux만 썼을 때 state가 모두 초기화 될 때로 로그인을 유지할 수 있습니다.

유저가 성공적으로 인증 되었으면 redux로 로그인 처리를 하면 됩니다.

 

그런데 어떻게 체크를 해야 할까요?

 

쿠키나 LS에서 jwt를 추출합니다. 그 이후 백단에 보내서 jwt를 디코드하고, payload에 담긴 식별자로 DB에서 해당 유저의 정보를 찾은 후, 존재하면 로그인처리해주면 됩니다.

 

 

ii) 라우트 이동 시에는 굳이 DB에 유저 인가 확인을 거치지 않고 Redux로 해결하면 됩니다.

 

 


p.s ) kakao javascript SDK 설치 및 활용

react-kakao-login이 아니라 직접 sdk를 이용하고 싶다면 다음과 같이 작성하면 됩니다.

 

cdn을 public - index.html에 넣어 줍니다. 이럼으로써 Kakao 클래스가 전역 객체화됩니다.

<script src="//developers.kakao.com/sdk/js/kakao.min.js"></script>

 

그런데 이제 일반 자바스크립트에서 사용하듯, 곧바로 Kakao 메서드를 사용하는 것이 아니라 전역 객체인 window에서 사용해야 합니다.

useEffect(() => {

  window.Kakao.init("발급 받은 js키");
  
  // 잘 동작하는가?
  console.log(window.Kakao.isInitialized()); // true
  
}, []);

 

SDK를 이용하면 다음과 같이 작성할 수 있겠습니다.

componentDidMount(){
   window.Kakao.Auth.createLoginButton({
      container: '#kakao-login-btn',
      success: function(authObj) {
    // 로그인 성공시, API를 호출합니다.
       window.Kakao.API.request({
          url: '/v2/user/me',
          success: function(res) {
            alert(JSON.stringify(res));
      },
      fail: function(error) {
        alert(JSON.stringify(error));
      }
    });
  },
  fail: function(err) {
    alert(JSON.stringify(err));
  }
})

  }

 render() {
    window.Kakao.init('발급 받은 js 키');

return (
  <div>
  <a id="kakao-login-btn"></a>
  </div>
);
  }
}

 

 

 

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체