bluegram - 8일차

박상은·2021년 12월 20일
0

🍃 blegram

목록 보기
12/20

1. 카카오 로그인 구현

passport-kakao를 이용해서 구현했습니다.

  • 개발 순서
  1. 카카오 개발자에서 애플리케이션 생성
  2. 플랫폼에서 웹사이트 도메인 등록
  3. 고급설정에서 로그아웃 URI 등록
  4. 동의항목 설정

위 4가지를 등록한 후에 REST API KEY를 이용해서 카카오에 로그인 및 로그아웃 요청을 보낼 수 있습니다.

REST API KEY를 아래의 clinetID에 넣어주면 카카오톡에서 확인 후 토큰들과 유저가 허용한 데이터를 보내줍니다.
해당 데이터와 토큰을 가지고 유저를 인증하는데 사용하면 됩니다.

  • accessToken은 추후에 로그아웃하는데 사용하게 됩니다.

  • /passport/kakao.js

import passport from "passport";
import { Strategy as KakaoStrategy } from "passport-kakao";
import db from "../models/index.js";

const { User, Image } = db;

const passportKakaoConfig = () => passport.use(
  new KakaoStrategy(
    {
      clientID: process.env.KAKAO_KEY,
      callbackURL: "/auth/kakao/callback"
    },
    async (accessToken, refreshToken, profile, done) => {
      const { id: snsId, provider, username: name } = profile;
      const { profile_image_url: url } = JSON.parse(profile._raw).kakao_account.profile;

      try {
        const exUser = await User.findOne({
          where: {
            snsId,
            provider,
            name,
          },
        });

        if(exUser){
          // 프로필 이미지가 변경될 가능성이 높으니 로그인할 때마다 새로 업데이트
          await Image.update(
            { url },
            {
              where: {
                UserId: exUser._id
              }
            }
          );
        
          return done(null, { user: exUser, accessToken });
        } else {
          const createdUser = await User.create({
            snsId,
            provider,
            name,
          });

          await Image.create({
            url,
            UserId: createdUser._id
          });
          return done(null, { user: createdUser, accessToken });
        }
      } catch (error) {
        done(error);
      }
    }
  )
);

export default passportKakaoConfig;
// 카카오 로그인
router.get("/kakao", isNotLoggedIn, passport.authenticate("kakao"));

router.get("/kakao/callback", passport.authenticate("kakao", {
  failureRedirect: "/"
}), (req, res) => {
  res.redirect(process.env.CLIENT_URL);
});

// 로그아웃
router.delete("/", isLoggedIn, async (req, res, next) => {
  if(req.user.accessToken){
    try {
      await axios.post("https://kapi.kakao.com/v1/user/unlink", null, {
        headers: {
          "Authorization": `Bearer ${req.user.accessToken}`,
        }
      });
    } catch (error) {
      return next(error)
    }
  }
  req.logout();
  req.session.destroy();
  res.status(200).json({ message: "로그아웃에 성공했습니다." });
});

2. 카카오 로그인의 실행 흐름

  1. 클라이언트에서 <a>를 이용해서 서버의 /auth/kakao로 접근
  2. 서버에서 passport.authenticate("kakao") 실행
  3. REST API KEYcallbackURL을 카카오로 전송해 주고 응답을 받음 ( 토큰들과 유저정보 )
  4. 응답받은 정보를 이용해서 DB에 유저 생성하고 accessToken을 세션에 저장
  5. 클라이언트로 세션 쿠키 전송
  6. 이후는 local전략과 같으므로 생략

여기서 특이한 점 중 한 가지는 클라이언트에서는 <a>를 이용해서 서버로 접근하는 것입니다.
이유는 redirect 요청이 올 때 cors문제가 발생하기 때문에 <a>로 접근했습니다.
( 사실 정확한 원인은 아직 이해하지 못했고 구글링으로 알아낸 방법으로 해결했습니다. )

두 번째 특이점은 accessTokenDB가 아닌 세션에 저장하는 것입니다.
세션은 서버 측 자원이기 때문에 각 유저마다 저장하면 기하급수적으로 메모리 사용량이 늘어날 수 있지만 많은 메모리를 사용하진 않고, 추후에 redis로 대체할 생각이기 때문에 큰 문제는 없다고 판단했습니다.

3. 스피너 구현

여기에서 css를 얻어서 Spinner 컴포넌트를 만들어서 Button 컴포넌트에 loading props가 true면 스피너를 보여주도록 구현했습니다.

마무리

1. 카카오 로그인 문제 및 어려웠던 점

로그아웃을 구현할 때는 고급설정에서 로그아웃 URI 등록해야 합니다.

또한 https://kapi.kakao.com/v1/user/unlink or https://kapi.kakao.com/v1/user/logout에 요청을 보내야 하고,
"Authorization": "Bearer " + req.user.accessToken와 같은 형태로 헤더에 토큰 값을 실어서 보내줘야 합니다.

2. 버튼 스피너

카카오 로그인 버튼 같은 경우에는 redux-saga를 거치지 않고 <a>를 이용해서 요청하므로 로그인 요청의 시작과 끝, 성공과 실패를 파악할 변수가 없어서 어떻게 spinner를 적용할지 고민해 보고 있습니다.

0개의 댓글